node.c 15.7 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
#define NODE_HTABLE_SIZE 512

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

48 49 50
static struct hlist_head node_htable[NODE_HTABLE_SIZE];
LIST_HEAD(tipc_node_list);
static u32 tipc_num_nodes;
51
static u32 tipc_num_links;
52
static DEFINE_SPINLOCK(node_list_lock);
53

54 55 56 57 58 59 60
struct tipc_sock_conn {
	u32 port;
	u32 peer_port;
	u32 peer_node;
	struct list_head list;
};

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
 * tipc_node_find - locate specified node object, if it exists
 */
struct tipc_node *tipc_node_find(u32 addr)
{
	struct tipc_node *node;

79
	if (unlikely(!in_own_cluster_exact(addr)))
80 81
		return NULL;

82 83
	rcu_read_lock();
	hlist_for_each_entry_rcu(node, &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(u32 addr)
P
Per Liden 已提交
94
{
95
	struct tipc_node *n_ptr, *temp_node;
P
Per Liden 已提交
96

97
	spin_lock_bh(&node_list_lock);
98

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

	n_ptr->addr = addr;
107
	spin_lock_init(&n_ptr->lock);
108 109
	INIT_HLIST_NODE(&n_ptr->hash);
	INIT_LIST_HEAD(&n_ptr->list);
110
	INIT_LIST_HEAD(&n_ptr->nsub);
111
	INIT_LIST_HEAD(&n_ptr->conn_sks);
112
	__skb_queue_head_init(&n_ptr->waiting_sks);
113

114
	hlist_add_head_rcu(&n_ptr->hash, &node_htable[tipc_hashfn(addr)]);
115

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

	tipc_num_nodes++;
125

126
	spin_unlock_bh(&node_list_lock);
P
Per Liden 已提交
127 128 129
	return n_ptr;
}

130
static void tipc_node_delete(struct tipc_node *n_ptr)
P
Per Liden 已提交
131
{
132 133 134
	list_del_rcu(&n_ptr->list);
	hlist_del_rcu(&n_ptr->hash);
	kfree_rcu(n_ptr, rcu);
135

136
	tipc_num_nodes--;
P
Per Liden 已提交
137 138
}

139 140 141 142 143 144 145 146 147 148
void tipc_node_stop(void)
{
	struct tipc_node *node, *t_node;

	spin_lock_bh(&node_list_lock);
	list_for_each_entry_safe(node, t_node, &tipc_node_list, list)
		tipc_node_delete(node);
	spin_unlock_bh(&node_list_lock);
}

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
int tipc_node_add_conn(u32 dnode, u32 port, u32 peer_port)
{
	struct tipc_node *node;
	struct tipc_sock_conn *conn;

	if (in_own_node(dnode))
		return 0;

	node = tipc_node_find(dnode);
	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;
}

void tipc_node_remove_conn(u32 dnode, u32 port)
{
	struct tipc_node *node;
	struct tipc_sock_conn *conn, *safe;

	if (in_own_node(dnode))
		return;

	node = tipc_node_find(dnode);
	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);
}

void tipc_node_abort_sock_conns(struct list_head *conns)
{
	struct tipc_sock_conn *conn, *safe;
	struct sk_buff *buf;

	list_for_each_entry_safe(conn, safe, conns, list) {
		buf = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG,
				      SHORT_H_SIZE, 0, tipc_own_addr,
				      conn->peer_node, conn->port,
				      conn->peer_port, TIPC_ERR_NO_NODE);
		if (likely(buf))
			tipc_sk_rcv(buf);
		list_del(&conn->list);
		kfree(conn);
	}
}

P
Per Liden 已提交
214
/**
215
 * tipc_node_link_up - handle addition of link
216
 *
P
Per Liden 已提交
217 218
 * Link becomes active (alone or shared) or standby, depending on its priority.
 */
219
void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
P
Per Liden 已提交
220
{
221
	struct tipc_link **active = &n_ptr->active_links[0];
P
Per Liden 已提交
222

223
	n_ptr->working_links++;
Y
Ying Xue 已提交
224 225 226
	n_ptr->action_flags |= TIPC_NOTIFY_LINK_UP;
	n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id;

227
	pr_info("Established link <%s> on network plane %c\n",
228
		l_ptr->name, l_ptr->net_plane);
229

P
Per Liden 已提交
230 231 232
	if (!active[0]) {
		active[0] = active[1] = l_ptr;
		node_established_contact(n_ptr);
233
		goto exit;
P
Per Liden 已提交
234
	}
235
	if (l_ptr->priority < active[0]->priority) {
236
		pr_info("New link <%s> becomes standby\n", l_ptr->name);
237
		goto exit;
P
Per Liden 已提交
238
	}
239
	tipc_link_dup_queue_xmit(active[0], l_ptr);
240
	if (l_ptr->priority == active[0]->priority) {
P
Per Liden 已提交
241
		active[0] = l_ptr;
242
		goto exit;
P
Per Liden 已提交
243
	}
244
	pr_info("Old link <%s> becomes standby\n", active[0]->name);
245
	if (active[1] != active[0])
246
		pr_info("Old link <%s> becomes standby\n", active[1]->name);
P
Per Liden 已提交
247
	active[0] = active[1] = l_ptr;
248 249 250 251
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 已提交
252 253 254 255 256
}

/**
 * node_select_active_links - select active link
 */
257
static void node_select_active_links(struct tipc_node *n_ptr)
P
Per Liden 已提交
258
{
259
	struct tipc_link **active = &n_ptr->active_links[0];
P
Per Liden 已提交
260 261 262
	u32 i;
	u32 highest_prio = 0;

263
	active[0] = active[1] = NULL;
P
Per Liden 已提交
264 265

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

268
		if (!l_ptr || !tipc_link_is_up(l_ptr) ||
P
Per Liden 已提交
269 270 271 272
		    (l_ptr->priority < highest_prio))
			continue;

		if (l_ptr->priority > highest_prio) {
273
			highest_prio = l_ptr->priority;
P
Per Liden 已提交
274 275 276 277 278 279 280 281
			active[0] = active[1] = l_ptr;
		} else {
			active[1] = l_ptr;
		}
	}
}

/**
282
 * tipc_node_link_down - handle loss of link
P
Per Liden 已提交
283
 */
284
void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
P
Per Liden 已提交
285
{
286
	struct tipc_link **active;
P
Per Liden 已提交
287

288
	n_ptr->working_links--;
Y
Ying Xue 已提交
289 290
	n_ptr->action_flags |= TIPC_NOTIFY_LINK_DOWN;
	n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id;
291

292
	if (!tipc_link_is_active(l_ptr)) {
293
		pr_info("Lost standby link <%s> on network plane %c\n",
294
			l_ptr->name, l_ptr->net_plane);
P
Per Liden 已提交
295 296
		return;
	}
297
	pr_info("Lost link <%s> on network plane %c\n",
298
		l_ptr->name, l_ptr->net_plane);
P
Per Liden 已提交
299 300 301 302 303 304 305 306

	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);
307
	if (tipc_node_is_up(n_ptr))
308
		tipc_link_failover_send_queue(l_ptr);
309
	else
P
Per Liden 已提交
310
		node_lost_contact(n_ptr);
311 312 313 314 315 316 317 318 319 320 321 322 323

	/* 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. */
	if (n_ptr->addr == tipc_own_addr) {
		n_ptr->act_mtus[0] = MAX_MSG_SIZE;
		n_ptr->act_mtus[1] = MAX_MSG_SIZE;
	}
P
Per Liden 已提交
324 325
}

326
int tipc_node_active_links(struct tipc_node *n_ptr)
P
Per Liden 已提交
327
{
328
	return n_ptr->active_links[0] != NULL;
P
Per Liden 已提交
329 330
}

331
int tipc_node_is_up(struct tipc_node *n_ptr)
P
Per Liden 已提交
332
{
333
	return tipc_node_active_links(n_ptr);
P
Per Liden 已提交
334 335
}

336
void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
P
Per Liden 已提交
337
{
338
	n_ptr->links[l_ptr->bearer_id] = l_ptr;
339 340 341
	spin_lock_bh(&node_list_lock);
	tipc_num_links++;
	spin_unlock_bh(&node_list_lock);
342
	n_ptr->link_cnt++;
P
Per Liden 已提交
343 344
}

345
void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
P
Per Liden 已提交
346
{
347 348 349
	int i;

	for (i = 0; i < MAX_BEARERS; i++) {
J
Jon Paul Maloy 已提交
350 351 352
		if (l_ptr != n_ptr->links[i])
			continue;
		n_ptr->links[i] = NULL;
353 354 355
		spin_lock_bh(&node_list_lock);
		tipc_num_links--;
		spin_unlock_bh(&node_list_lock);
J
Jon Paul Maloy 已提交
356
		n_ptr->link_cnt--;
357
	}
P
Per Liden 已提交
358 359
}

360
static void node_established_contact(struct tipc_node *n_ptr)
P
Per Liden 已提交
361
{
Y
Ying Xue 已提交
362
	n_ptr->action_flags |= TIPC_NOTIFY_NODE_UP;
363
	n_ptr->bclink.oos_state = 0;
364 365
	n_ptr->bclink.acked = tipc_bclink_get_last_sent();
	tipc_bclink_add_node(n_ptr->addr);
P
Per Liden 已提交
366 367
}

368
static void node_lost_contact(struct tipc_node *n_ptr)
P
Per Liden 已提交
369 370 371 372
{
	char addr_string[16];
	u32 i;

373 374
	pr_info("Lost contact with %s\n",
		tipc_addr_string_fill(addr_string, n_ptr->addr));
375 376

	/* Flush broadcast link info associated with lost node */
377
	if (n_ptr->bclink.recv_permitted) {
378
		kfree_skb_list(n_ptr->bclink.deferred_head);
379
		n_ptr->bclink.deferred_size = 0;
380

381 382 383
		if (n_ptr->bclink.reasm_buf) {
			kfree_skb(n_ptr->bclink.reasm_buf);
			n_ptr->bclink.reasm_buf = NULL;
384 385
		}

386
		tipc_bclink_remove_node(n_ptr->addr);
387
		tipc_bclink_acknowledge(n_ptr, INVALID_LINK_SEQ);
P
Per Liden 已提交
388

389
		n_ptr->bclink.recv_permitted = false;
390
	}
P
Per Liden 已提交
391 392 393

	/* Abort link changeover */
	for (i = 0; i < MAX_BEARERS; i++) {
394
		struct tipc_link *l_ptr = n_ptr->links[i];
395
		if (!l_ptr)
P
Per Liden 已提交
396 397 398
			continue;
		l_ptr->reset_checkpoint = l_ptr->next_in_no;
		l_ptr->exp_msg_count = 0;
399
		tipc_link_reset_fragments(l_ptr);
P
Per Liden 已提交
400 401
	}

402 403
	n_ptr->action_flags &= ~TIPC_WAIT_OWN_LINKS_DOWN;

404 405 406
	/* Notify subscribers and prevent re-contact with node until
	 * cleanup is done.
	 */
407 408
	n_ptr->action_flags |= TIPC_WAIT_PEER_LINKS_DOWN |
			       TIPC_NOTIFY_NODE_DOWN;
P
Per Liden 已提交
409 410
}

411
struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
P
Per Liden 已提交
412 413 414
{
	u32 domain;
	struct sk_buff *buf;
415
	struct tipc_node *n_ptr;
416
	struct tipc_node_info node_info;
417
	u32 payload_size;
P
Per Liden 已提交
418 419

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

A
Al Viro 已提交
422
	domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
423 424 425
	if (!tipc_addr_domain_valid(domain))
		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
						   " (network address)");
P
Per Liden 已提交
426

427
	spin_lock_bh(&node_list_lock);
428
	if (!tipc_num_nodes) {
429
		spin_unlock_bh(&node_list_lock);
430
		return tipc_cfg_reply_none();
431
	}
P
Per Liden 已提交
432

433
	/* For now, get space for all other nodes */
434
	payload_size = TLV_SPACE(sizeof(node_info)) * tipc_num_nodes;
435
	if (payload_size > 32768u) {
436
		spin_unlock_bh(&node_list_lock);
437 438
		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
						   " (too many nodes)");
439
	}
440 441
	spin_unlock_bh(&node_list_lock);

442
	buf = tipc_cfg_reply_alloc(payload_size);
443
	if (!buf)
P
Per Liden 已提交
444 445 446
		return NULL;

	/* Add TLVs for all nodes in scope */
447 448
	rcu_read_lock();
	list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
449
		if (!tipc_in_scope(domain, n_ptr->addr))
P
Per Liden 已提交
450
			continue;
451 452 453
		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,
454
				    &node_info, sizeof(node_info));
P
Per Liden 已提交
455
	}
456
	rcu_read_unlock();
P
Per Liden 已提交
457 458 459
	return buf;
}

460
struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
P
Per Liden 已提交
461 462 463
{
	u32 domain;
	struct sk_buff *buf;
464
	struct tipc_node *n_ptr;
465
	struct tipc_link_info link_info;
466
	u32 payload_size;
P
Per Liden 已提交
467 468

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

A
Al Viro 已提交
471
	domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
472 473 474
	if (!tipc_addr_domain_valid(domain))
		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
						   " (network address)");
P
Per Liden 已提交
475

476
	if (!tipc_own_addr)
477 478
		return tipc_cfg_reply_none();

479
	spin_lock_bh(&node_list_lock);
480
	/* Get space for all unicast links + broadcast link */
481
	payload_size = TLV_SPACE((sizeof(link_info)) * (tipc_num_links + 1));
482
	if (payload_size > 32768u) {
483
		spin_unlock_bh(&node_list_lock);
484 485
		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
						   " (too many links)");
486
	}
487 488
	spin_unlock_bh(&node_list_lock);

489
	buf = tipc_cfg_reply_alloc(payload_size);
490
	if (!buf)
P
Per Liden 已提交
491 492 493
		return NULL;

	/* Add TLV for broadcast link */
494
	link_info.dest = htonl(tipc_cluster_mask(tipc_own_addr));
495
	link_info.up = htonl(1);
496
	strlcpy(link_info.str, tipc_bclink_name, TIPC_MAX_LINK_NAME);
497
	tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
P
Per Liden 已提交
498 499

	/* Add TLVs for any other links in scope */
500 501
	rcu_read_lock();
	list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
502
		u32 i;
P
Per Liden 已提交
503

504
		if (!tipc_in_scope(domain, n_ptr->addr))
P
Per Liden 已提交
505
			continue;
506
		tipc_node_lock(n_ptr);
507 508 509 510 511 512 513
		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,
514
					    &link_info, sizeof(link_info));
515
		}
516
		tipc_node_unlock(n_ptr);
P
Per Liden 已提交
517
	}
518
	rcu_read_unlock();
P
Per Liden 已提交
519 520
	return buf;
}
E
Erik Hugne 已提交
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535

/**
 * 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
 */
int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len)
{
	struct tipc_link *link;
	struct tipc_node *node = tipc_node_find(addr);

E
Erik Hugne 已提交
536
	if ((bearer_id >= MAX_BEARERS) || !node)
E
Erik Hugne 已提交
537 538 539 540 541 542 543 544 545 546 547
		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;
}
548 549 550 551

void tipc_node_unlock(struct tipc_node *node)
{
	LIST_HEAD(nsub_list);
552
	LIST_HEAD(conn_sks);
553
	struct sk_buff_head waiting_sks;
554
	u32 addr = 0;
Y
Ying Xue 已提交
555 556
	int flags = node->action_flags;
	u32 link_id = 0;
557

Y
Ying Xue 已提交
558
	if (likely(!flags)) {
559 560 561 562
		spin_unlock_bh(&node->lock);
		return;
	}

Y
Ying Xue 已提交
563 564
	addr = node->addr;
	link_id = node->link_id;
565
	__skb_queue_head_init(&waiting_sks);
Y
Ying Xue 已提交
566 567

	if (flags & TIPC_WAKEUP_USERS)
568
		skb_queue_splice_init(&node->waiting_sks, &waiting_sks);
Y
Ying Xue 已提交
569 570

	if (flags & TIPC_NOTIFY_NODE_DOWN) {
571
		list_replace_init(&node->nsub, &nsub_list);
572
		list_replace_init(&node->conn_sks, &conn_sks);
573
	}
Y
Ying Xue 已提交
574 575 576 577 578
	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);

579 580
	spin_unlock_bh(&node->lock);

581 582 583
	while (!skb_queue_empty(&waiting_sks))
		tipc_sk_rcv(__skb_dequeue(&waiting_sks));

584 585 586
	if (!list_empty(&conn_sks))
		tipc_node_abort_sock_conns(&conn_sks);

587 588
	if (!list_empty(&nsub_list))
		tipc_nodesub_notify(&nsub_list);
589

590 591 592
	if (flags & TIPC_WAKEUP_BCAST_USERS)
		tipc_bclink_wakeup_users();

Y
Ying Xue 已提交
593
	if (flags & TIPC_NOTIFY_NODE_UP)
594
		tipc_named_node_up(addr);
Y
Ying Xue 已提交
595 596 597 598 599 600 601 602

	if (flags & TIPC_NOTIFY_LINK_UP)
		tipc_nametbl_publish(TIPC_LINK_STATE, addr, addr,
				     TIPC_NODE_SCOPE, link_id, addr);

	if (flags & TIPC_NOTIFY_LINK_DOWN)
		tipc_nametbl_withdraw(TIPC_LINK_STATE, addr,
				      link_id, addr);
603
}