]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - net/tipc/node.c
Merge tag 'wireless-drivers-next-for-davem-2015-02-07' of git://git.kernel.org/pub...
[mirror_ubuntu-bionic-kernel.git] / net / tipc / node.c
CommitLineData
b97bf3fd
PL
1/*
2 * net/tipc/node.c: TIPC node management routines
c4307285 3 *
16e166b8 4 * Copyright (c) 2000-2006, 2012-2014, Ericsson AB
46651c59 5 * Copyright (c) 2005-2006, 2010-2014, Wind River Systems
b97bf3fd
PL
6 * All rights reserved.
7 *
9ea1fd3c 8 * Redistribution and use in source and binary forms, with or without
b97bf3fd
PL
9 * modification, are permitted provided that the following conditions are met:
10 *
9ea1fd3c
PL
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the names of the copyright holders nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
b97bf3fd 19 *
9ea1fd3c
PL
20 * Alternatively, this software may be distributed under the terms of the
21 * GNU General Public License ("GPL") version 2 as published by the Free
22 * Software Foundation.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
b97bf3fd
PL
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#include "core.h"
38#include "config.h"
39#include "node.h"
b97bf3fd 40#include "name_distr.h"
50100a5e 41#include "socket.h"
b97bf3fd 42
6c00055a
DM
43static void node_lost_contact(struct tipc_node *n_ptr);
44static void node_established_contact(struct tipc_node *n_ptr);
b97bf3fd 45
02be61a9
JPM
46struct tipc_sock_conn {
47 u32 port;
48 u32 peer_port;
49 u32 peer_node;
50 struct list_head list;
51};
52
3e4b6ab5
RA
53static const struct nla_policy tipc_nl_node_policy[TIPC_NLA_NODE_MAX + 1] = {
54 [TIPC_NLA_NODE_UNSPEC] = { .type = NLA_UNSPEC },
55 [TIPC_NLA_NODE_ADDR] = { .type = NLA_U32 },
56 [TIPC_NLA_NODE_UP] = { .type = NLA_FLAG }
57};
58
a635b46b
AS
59/*
60 * A trivial power-of-two bitmask technique is used for speed, since this
61 * operation is done for every incoming TIPC packet. The number of hash table
62 * entries has been chosen so that no hash chain exceeds 8 nodes and will
63 * usually be much smaller (typically only a single node).
64 */
872f24db 65static unsigned int tipc_hashfn(u32 addr)
a635b46b
AS
66{
67 return addr & (NODE_HTABLE_SIZE - 1);
68}
69
1ec2bb08 70/*
672d99e1
AS
71 * tipc_node_find - locate specified node object, if it exists
72 */
f2f9800d 73struct tipc_node *tipc_node_find(struct net *net, u32 addr)
672d99e1 74{
f2f9800d 75 struct tipc_net *tn = net_generic(net, tipc_net_id);
672d99e1 76 struct tipc_node *node;
672d99e1 77
34747539 78 if (unlikely(!in_own_cluster_exact(net, addr)))
672d99e1
AS
79 return NULL;
80
6c7a762e 81 rcu_read_lock();
f2f9800d
YX
82 hlist_for_each_entry_rcu(node, &tn->node_htable[tipc_hashfn(addr)],
83 hash) {
46651c59 84 if (node->addr == addr) {
6c7a762e 85 rcu_read_unlock();
672d99e1 86 return node;
46651c59 87 }
672d99e1 88 }
6c7a762e 89 rcu_read_unlock();
672d99e1
AS
90 return NULL;
91}
92
f2f9800d 93struct tipc_node *tipc_node_create(struct net *net, u32 addr)
b97bf3fd 94{
f2f9800d 95 struct tipc_net *tn = net_generic(net, tipc_net_id);
672d99e1 96 struct tipc_node *n_ptr, *temp_node;
b97bf3fd 97
f2f9800d 98 spin_lock_bh(&tn->node_list_lock);
b45db71b
JPM
99 n_ptr = tipc_node_find(net, addr);
100 if (n_ptr)
101 goto exit;
5af54792 102 n_ptr = kzalloc(sizeof(*n_ptr), GFP_ATOMIC);
a10bd924 103 if (!n_ptr) {
2cf8aa19 104 pr_warn("Node creation failed, no memory\n");
b45db71b 105 goto exit;
a10bd924 106 }
a10bd924 107 n_ptr->addr = addr;
f2f9800d 108 n_ptr->net = net;
51a8e4de 109 spin_lock_init(&n_ptr->lock);
672d99e1
AS
110 INIT_HLIST_NODE(&n_ptr->hash);
111 INIT_LIST_HEAD(&n_ptr->list);
a8f48af5 112 INIT_LIST_HEAD(&n_ptr->publ_list);
02be61a9 113 INIT_LIST_HEAD(&n_ptr->conn_sks);
bc6fecd4 114 __skb_queue_head_init(&n_ptr->bclink.deferred_queue);
f2f9800d 115 hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]);
f2f9800d 116 list_for_each_entry_rcu(temp_node, &tn->node_list, list) {
672d99e1
AS
117 if (n_ptr->addr < temp_node->addr)
118 break;
119 }
6c7a762e 120 list_add_tail_rcu(&n_ptr->list, &temp_node->list);
aecb9bb8 121 n_ptr->action_flags = TIPC_WAIT_PEER_LINKS_DOWN;
fc0eea69 122 n_ptr->signature = INVALID_NODE_SIG;
f2f9800d 123 tn->num_nodes++;
b45db71b 124exit:
f2f9800d 125 spin_unlock_bh(&tn->node_list_lock);
b97bf3fd
PL
126 return n_ptr;
127}
128
f2f9800d 129static void tipc_node_delete(struct tipc_net *tn, struct tipc_node *n_ptr)
b97bf3fd 130{
6c7a762e
YX
131 list_del_rcu(&n_ptr->list);
132 hlist_del_rcu(&n_ptr->hash);
133 kfree_rcu(n_ptr, rcu);
8f92df6a 134
f2f9800d 135 tn->num_nodes--;
b97bf3fd
PL
136}
137
f2f9800d 138void tipc_node_stop(struct net *net)
46651c59 139{
f2f9800d 140 struct tipc_net *tn = net_generic(net, tipc_net_id);
46651c59
YX
141 struct tipc_node *node, *t_node;
142
f2f9800d
YX
143 spin_lock_bh(&tn->node_list_lock);
144 list_for_each_entry_safe(node, t_node, &tn->node_list, list)
145 tipc_node_delete(tn, node);
146 spin_unlock_bh(&tn->node_list_lock);
46651c59
YX
147}
148
f2f9800d 149int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port)
02be61a9
JPM
150{
151 struct tipc_node *node;
152 struct tipc_sock_conn *conn;
153
34747539 154 if (in_own_node(net, dnode))
02be61a9
JPM
155 return 0;
156
f2f9800d 157 node = tipc_node_find(net, dnode);
02be61a9
JPM
158 if (!node) {
159 pr_warn("Connecting sock to node 0x%x failed\n", dnode);
160 return -EHOSTUNREACH;
161 }
162 conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
163 if (!conn)
164 return -EHOSTUNREACH;
165 conn->peer_node = dnode;
166 conn->port = port;
167 conn->peer_port = peer_port;
168
169 tipc_node_lock(node);
170 list_add_tail(&conn->list, &node->conn_sks);
171 tipc_node_unlock(node);
172 return 0;
173}
174
f2f9800d 175void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port)
02be61a9
JPM
176{
177 struct tipc_node *node;
178 struct tipc_sock_conn *conn, *safe;
179
34747539 180 if (in_own_node(net, dnode))
02be61a9
JPM
181 return;
182
f2f9800d 183 node = tipc_node_find(net, dnode);
02be61a9
JPM
184 if (!node)
185 return;
186
187 tipc_node_lock(node);
188 list_for_each_entry_safe(conn, safe, &node->conn_sks, list) {
189 if (port != conn->port)
190 continue;
191 list_del(&conn->list);
192 kfree(conn);
193 }
194 tipc_node_unlock(node);
195}
196
b97bf3fd 197/**
4323add6 198 * tipc_node_link_up - handle addition of link
c4307285 199 *
b97bf3fd
PL
200 * Link becomes active (alone or shared) or standby, depending on its priority.
201 */
a18c4bc3 202void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
b97bf3fd 203{
a18c4bc3 204 struct tipc_link **active = &n_ptr->active_links[0];
b97bf3fd 205
5392d646 206 n_ptr->working_links++;
7b8613e0
YX
207 n_ptr->action_flags |= TIPC_NOTIFY_LINK_UP;
208 n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id;
209
3fa9cacd
EH
210 pr_debug("Established link <%s> on network plane %c\n",
211 l_ptr->name, l_ptr->net_plane);
c4307285 212
b97bf3fd 213 if (!active[0]) {
b97bf3fd
PL
214 active[0] = active[1] = l_ptr;
215 node_established_contact(n_ptr);
16e166b8 216 goto exit;
b97bf3fd 217 }
c4307285 218 if (l_ptr->priority < active[0]->priority) {
3fa9cacd 219 pr_debug("New link <%s> becomes standby\n", l_ptr->name);
16e166b8 220 goto exit;
b97bf3fd 221 }
247f0f3c 222 tipc_link_dup_queue_xmit(active[0], l_ptr);
c4307285 223 if (l_ptr->priority == active[0]->priority) {
b97bf3fd 224 active[0] = l_ptr;
16e166b8 225 goto exit;
b97bf3fd 226 }
3fa9cacd 227 pr_debug("Old link <%s> becomes standby\n", active[0]->name);
a10bd924 228 if (active[1] != active[0])
3fa9cacd 229 pr_debug("Old link <%s> becomes standby\n", active[1]->name);
b97bf3fd 230 active[0] = active[1] = l_ptr;
16e166b8
JPM
231exit:
232 /* Leave room for changeover header when returning 'mtu' to users: */
233 n_ptr->act_mtus[0] = active[0]->max_pkt - INT_H_SIZE;
234 n_ptr->act_mtus[1] = active[1]->max_pkt - INT_H_SIZE;
b97bf3fd
PL
235}
236
237/**
238 * node_select_active_links - select active link
239 */
6c00055a 240static void node_select_active_links(struct tipc_node *n_ptr)
b97bf3fd 241{
a18c4bc3 242 struct tipc_link **active = &n_ptr->active_links[0];
b97bf3fd
PL
243 u32 i;
244 u32 highest_prio = 0;
245
c4307285 246 active[0] = active[1] = NULL;
b97bf3fd
PL
247
248 for (i = 0; i < MAX_BEARERS; i++) {
a18c4bc3 249 struct tipc_link *l_ptr = n_ptr->links[i];
b97bf3fd 250
4323add6 251 if (!l_ptr || !tipc_link_is_up(l_ptr) ||
b97bf3fd
PL
252 (l_ptr->priority < highest_prio))
253 continue;
254
255 if (l_ptr->priority > highest_prio) {
c4307285 256 highest_prio = l_ptr->priority;
b97bf3fd
PL
257 active[0] = active[1] = l_ptr;
258 } else {
259 active[1] = l_ptr;
260 }
261 }
262}
263
264/**
4323add6 265 * tipc_node_link_down - handle loss of link
b97bf3fd 266 */
a18c4bc3 267void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
b97bf3fd 268{
34747539 269 struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
a18c4bc3 270 struct tipc_link **active;
b97bf3fd 271
5392d646 272 n_ptr->working_links--;
7b8613e0
YX
273 n_ptr->action_flags |= TIPC_NOTIFY_LINK_DOWN;
274 n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id;
5392d646 275
4323add6 276 if (!tipc_link_is_active(l_ptr)) {
3fa9cacd
EH
277 pr_debug("Lost standby link <%s> on network plane %c\n",
278 l_ptr->name, l_ptr->net_plane);
b97bf3fd
PL
279 return;
280 }
3fa9cacd
EH
281 pr_debug("Lost link <%s> on network plane %c\n",
282 l_ptr->name, l_ptr->net_plane);
b97bf3fd
PL
283
284 active = &n_ptr->active_links[0];
285 if (active[0] == l_ptr)
286 active[0] = active[1];
287 if (active[1] == l_ptr)
288 active[1] = active[0];
289 if (active[0] == l_ptr)
290 node_select_active_links(n_ptr);
c4307285 291 if (tipc_node_is_up(n_ptr))
170b3927 292 tipc_link_failover_send_queue(l_ptr);
c4307285 293 else
b97bf3fd 294 node_lost_contact(n_ptr);
16e166b8
JPM
295
296 /* Leave room for changeover header when returning 'mtu' to users: */
297 if (active[0]) {
298 n_ptr->act_mtus[0] = active[0]->max_pkt - INT_H_SIZE;
299 n_ptr->act_mtus[1] = active[1]->max_pkt - INT_H_SIZE;
300 return;
301 }
302
303 /* Loopback link went down? No fragmentation needed from now on. */
34747539 304 if (n_ptr->addr == tn->own_addr) {
16e166b8
JPM
305 n_ptr->act_mtus[0] = MAX_MSG_SIZE;
306 n_ptr->act_mtus[1] = MAX_MSG_SIZE;
307 }
b97bf3fd
PL
308}
309
8f19afb2 310int tipc_node_active_links(struct tipc_node *n_ptr)
b97bf3fd 311{
76ae0d71 312 return n_ptr->active_links[0] != NULL;
b97bf3fd
PL
313}
314
6c00055a 315int tipc_node_is_up(struct tipc_node *n_ptr)
b97bf3fd 316{
8f19afb2 317 return tipc_node_active_links(n_ptr);
b97bf3fd
PL
318}
319
a18c4bc3 320void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
b97bf3fd 321{
f2f9800d
YX
322 struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
323
7a2f7d18 324 n_ptr->links[l_ptr->bearer_id] = l_ptr;
f2f9800d
YX
325 spin_lock_bh(&tn->node_list_lock);
326 tn->num_links++;
327 spin_unlock_bh(&tn->node_list_lock);
37b9c08a 328 n_ptr->link_cnt++;
b97bf3fd
PL
329}
330
a18c4bc3 331void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
b97bf3fd 332{
f2f9800d 333 struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
7d33939f
JPM
334 int i;
335
336 for (i = 0; i < MAX_BEARERS; i++) {
074bb43e
JPM
337 if (l_ptr != n_ptr->links[i])
338 continue;
339 n_ptr->links[i] = NULL;
f2f9800d
YX
340 spin_lock_bh(&tn->node_list_lock);
341 tn->num_links--;
342 spin_unlock_bh(&tn->node_list_lock);
074bb43e 343 n_ptr->link_cnt--;
7d33939f 344 }
b97bf3fd
PL
345}
346
6c00055a 347static void node_established_contact(struct tipc_node *n_ptr)
b97bf3fd 348{
aecb9bb8 349 n_ptr->action_flags |= TIPC_NOTIFY_NODE_UP;
c64f7a6a 350 n_ptr->bclink.oos_state = 0;
1da46568
YX
351 n_ptr->bclink.acked = tipc_bclink_get_last_sent(n_ptr->net);
352 tipc_bclink_add_node(n_ptr->net, n_ptr->addr);
b97bf3fd
PL
353}
354
6c00055a 355static void node_lost_contact(struct tipc_node *n_ptr)
b97bf3fd 356{
b97bf3fd 357 char addr_string[16];
708ac32c
JPM
358 struct tipc_sock_conn *conn, *safe;
359 struct list_head *conns = &n_ptr->conn_sks;
360 struct sk_buff *skb;
361 struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
362 uint i;
b97bf3fd 363
3fa9cacd
EH
364 pr_debug("Lost contact with %s\n",
365 tipc_addr_string_fill(addr_string, n_ptr->addr));
c5bd4d85
AS
366
367 /* Flush broadcast link info associated with lost node */
389dd9bc 368 if (n_ptr->bclink.recv_permitted) {
bc6fecd4 369 __skb_queue_purge(&n_ptr->bclink.deferred_queue);
c5bd4d85 370
37e22164
JPM
371 if (n_ptr->bclink.reasm_buf) {
372 kfree_skb(n_ptr->bclink.reasm_buf);
373 n_ptr->bclink.reasm_buf = NULL;
c5bd4d85
AS
374 }
375
1da46568 376 tipc_bclink_remove_node(n_ptr->net, n_ptr->addr);
36559591 377 tipc_bclink_acknowledge(n_ptr, INVALID_LINK_SEQ);
b97bf3fd 378
389dd9bc 379 n_ptr->bclink.recv_permitted = false;
c5bd4d85 380 }
b97bf3fd
PL
381
382 /* Abort link changeover */
383 for (i = 0; i < MAX_BEARERS; i++) {
a18c4bc3 384 struct tipc_link *l_ptr = n_ptr->links[i];
c4307285 385 if (!l_ptr)
b97bf3fd
PL
386 continue;
387 l_ptr->reset_checkpoint = l_ptr->next_in_no;
388 l_ptr->exp_msg_count = 0;
4323add6 389 tipc_link_reset_fragments(l_ptr);
7d24dcdb
JPM
390
391 /* Link marked for deletion after failover? => do it now */
392 if (l_ptr->flags & LINK_STOPPED)
393 tipc_link_delete(l_ptr);
b97bf3fd
PL
394 }
395
ca9cf06a
YX
396 n_ptr->action_flags &= ~TIPC_WAIT_OWN_LINKS_DOWN;
397
708ac32c
JPM
398 /* Prevent re-contact with node until cleanup is done */
399 n_ptr->action_flags |= TIPC_WAIT_PEER_LINKS_DOWN;
400
401 /* Notify publications from this node */
402 n_ptr->action_flags |= TIPC_NOTIFY_NODE_DOWN;
403
404 /* Notify sockets connected to node */
405 list_for_each_entry_safe(conn, safe, conns, list) {
406 skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG,
407 SHORT_H_SIZE, 0, tn->own_addr,
408 conn->peer_node, conn->port,
409 conn->peer_port, TIPC_ERR_NO_NODE);
410 if (likely(skb)) {
411 skb_queue_tail(n_ptr->inputq, skb);
412 n_ptr->action_flags |= TIPC_MSG_EVT;
413 }
414 list_del(&conn->list);
415 kfree(conn);
416 }
b97bf3fd
PL
417}
418
f2f9800d
YX
419struct sk_buff *tipc_node_get_nodes(struct net *net, const void *req_tlv_area,
420 int req_tlv_space)
b97bf3fd 421{
f2f9800d 422 struct tipc_net *tn = net_generic(net, tipc_net_id);
b97bf3fd
PL
423 u32 domain;
424 struct sk_buff *buf;
6c00055a 425 struct tipc_node *n_ptr;
c4307285 426 struct tipc_node_info node_info;
ea13847b 427 u32 payload_size;
b97bf3fd
PL
428
429 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
4323add6 430 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
b97bf3fd 431
3e6c8cd5 432 domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
4323add6
PL
433 if (!tipc_addr_domain_valid(domain))
434 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
435 " (network address)");
b97bf3fd 436
f2f9800d
YX
437 spin_lock_bh(&tn->node_list_lock);
438 if (!tn->num_nodes) {
439 spin_unlock_bh(&tn->node_list_lock);
c4307285 440 return tipc_cfg_reply_none();
1aad72d6 441 }
b97bf3fd 442
08c80e9a 443 /* For now, get space for all other nodes */
f2f9800d 444 payload_size = TLV_SPACE(sizeof(node_info)) * tn->num_nodes;
1aad72d6 445 if (payload_size > 32768u) {
f2f9800d 446 spin_unlock_bh(&tn->node_list_lock);
ea13847b
AS
447 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
448 " (too many nodes)");
1aad72d6 449 }
f2f9800d 450 spin_unlock_bh(&tn->node_list_lock);
2220646a 451
ea13847b 452 buf = tipc_cfg_reply_alloc(payload_size);
2220646a 453 if (!buf)
b97bf3fd
PL
454 return NULL;
455
456 /* Add TLVs for all nodes in scope */
6c7a762e 457 rcu_read_lock();
f2f9800d 458 list_for_each_entry_rcu(n_ptr, &tn->node_list, list) {
672d99e1 459 if (!tipc_in_scope(domain, n_ptr->addr))
b97bf3fd 460 continue;
c4307285
YH
461 node_info.addr = htonl(n_ptr->addr);
462 node_info.up = htonl(tipc_node_is_up(n_ptr));
463 tipc_cfg_append_tlv(buf, TIPC_TLV_NODE_INFO,
4323add6 464 &node_info, sizeof(node_info));
b97bf3fd 465 }
6c7a762e 466 rcu_read_unlock();
b97bf3fd
PL
467 return buf;
468}
469
f2f9800d
YX
470struct sk_buff *tipc_node_get_links(struct net *net, const void *req_tlv_area,
471 int req_tlv_space)
b97bf3fd 472{
f2f9800d 473 struct tipc_net *tn = net_generic(net, tipc_net_id);
b97bf3fd
PL
474 u32 domain;
475 struct sk_buff *buf;
6c00055a 476 struct tipc_node *n_ptr;
c4307285 477 struct tipc_link_info link_info;
ea13847b 478 u32 payload_size;
b97bf3fd
PL
479
480 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
4323add6 481 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
b97bf3fd 482
3e6c8cd5 483 domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
4323add6
PL
484 if (!tipc_addr_domain_valid(domain))
485 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
486 " (network address)");
b97bf3fd 487
34747539 488 if (!tn->own_addr)
c4307285
YH
489 return tipc_cfg_reply_none();
490
f2f9800d 491 spin_lock_bh(&tn->node_list_lock);
7a54d4a9 492 /* Get space for all unicast links + broadcast link */
f2f9800d 493 payload_size = TLV_SPACE((sizeof(link_info)) * (tn->num_links + 1));
1aad72d6 494 if (payload_size > 32768u) {
f2f9800d 495 spin_unlock_bh(&tn->node_list_lock);
ea13847b
AS
496 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
497 " (too many links)");
1aad72d6 498 }
f2f9800d 499 spin_unlock_bh(&tn->node_list_lock);
dde20266 500
ea13847b 501 buf = tipc_cfg_reply_alloc(payload_size);
dde20266 502 if (!buf)
b97bf3fd
PL
503 return NULL;
504
505 /* Add TLV for broadcast link */
34747539 506 link_info.dest = htonl(tipc_cluster_mask(tn->own_addr));
c4307285 507 link_info.up = htonl(1);
4b704d59 508 strlcpy(link_info.str, tipc_bclink_name, TIPC_MAX_LINK_NAME);
4323add6 509 tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
b97bf3fd
PL
510
511 /* Add TLVs for any other links in scope */
6c7a762e 512 rcu_read_lock();
f2f9800d 513 list_for_each_entry_rcu(n_ptr, &tn->node_list, list) {
c4307285 514 u32 i;
b97bf3fd 515
672d99e1 516 if (!tipc_in_scope(domain, n_ptr->addr))
b97bf3fd 517 continue;
1aad72d6 518 tipc_node_lock(n_ptr);
c4307285
YH
519 for (i = 0; i < MAX_BEARERS; i++) {
520 if (!n_ptr->links[i])
521 continue;
522 link_info.dest = htonl(n_ptr->addr);
523 link_info.up = htonl(tipc_link_is_up(n_ptr->links[i]));
524 strcpy(link_info.str, n_ptr->links[i]->name);
525 tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO,
4323add6 526 &link_info, sizeof(link_info));
c4307285 527 }
1aad72d6 528 tipc_node_unlock(n_ptr);
b97bf3fd 529 }
6c7a762e 530 rcu_read_unlock();
b97bf3fd
PL
531 return buf;
532}
78acb1f9
EH
533
534/**
535 * tipc_node_get_linkname - get the name of a link
536 *
537 * @bearer_id: id of the bearer
538 * @node: peer node address
539 * @linkname: link name output buffer
540 *
541 * Returns 0 on success
542 */
f2f9800d
YX
543int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 addr,
544 char *linkname, size_t len)
78acb1f9
EH
545{
546 struct tipc_link *link;
f2f9800d 547 struct tipc_node *node = tipc_node_find(net, addr);
78acb1f9 548
d7bb74c3 549 if ((bearer_id >= MAX_BEARERS) || !node)
78acb1f9
EH
550 return -EINVAL;
551 tipc_node_lock(node);
552 link = node->links[bearer_id];
553 if (link) {
554 strncpy(linkname, link->name, len);
555 tipc_node_unlock(node);
556 return 0;
557 }
558 tipc_node_unlock(node);
559 return -EINVAL;
560}
9db9fdd1
YX
561
562void tipc_node_unlock(struct tipc_node *node)
563{
f2f9800d 564 struct net *net = node->net;
ca0c4273 565 u32 addr = 0;
c637c103 566 u32 flags = node->action_flags;
7b8613e0 567 u32 link_id = 0;
708ac32c 568 struct list_head *publ_list;
c637c103 569 struct sk_buff_head *inputq = node->inputq;
708ac32c 570 struct sk_buff_head *namedq;
9db9fdd1 571
c637c103
JPM
572 if (likely(!flags || (flags == TIPC_MSG_EVT))) {
573 node->action_flags = 0;
9db9fdd1 574 spin_unlock_bh(&node->lock);
c637c103
JPM
575 if (flags == TIPC_MSG_EVT)
576 tipc_sk_rcv(net, inputq);
9db9fdd1
YX
577 return;
578 }
579
7b8613e0
YX
580 addr = node->addr;
581 link_id = node->link_id;
c637c103 582 namedq = node->namedq;
708ac32c 583 publ_list = &node->publ_list;
7b8613e0 584
cb1b7280
JPM
585 node->action_flags &= ~(TIPC_MSG_EVT |
586 TIPC_NOTIFY_NODE_DOWN | TIPC_NOTIFY_NODE_UP |
587 TIPC_NOTIFY_LINK_DOWN | TIPC_NOTIFY_LINK_UP |
588 TIPC_WAKEUP_BCAST_USERS | TIPC_BCAST_MSG_EVT |
c637c103 589 TIPC_NAMED_MSG_EVT);
7b8613e0 590
9db9fdd1
YX
591 spin_unlock_bh(&node->lock);
592
708ac32c
JPM
593 if (flags & TIPC_NOTIFY_NODE_DOWN)
594 tipc_publ_notify(net, publ_list, addr);
50100a5e 595
908344cd 596 if (flags & TIPC_WAKEUP_BCAST_USERS)
f2f9800d 597 tipc_bclink_wakeup_users(net);
908344cd 598
7b8613e0 599 if (flags & TIPC_NOTIFY_NODE_UP)
f2f9800d 600 tipc_named_node_up(net, addr);
7b8613e0
YX
601
602 if (flags & TIPC_NOTIFY_LINK_UP)
f2f9800d 603 tipc_nametbl_publish(net, TIPC_LINK_STATE, addr, addr,
7b8613e0
YX
604 TIPC_NODE_SCOPE, link_id, addr);
605
606 if (flags & TIPC_NOTIFY_LINK_DOWN)
f2f9800d 607 tipc_nametbl_withdraw(net, TIPC_LINK_STATE, addr,
7b8613e0 608 link_id, addr);
c637c103
JPM
609
610 if (flags & TIPC_MSG_EVT)
611 tipc_sk_rcv(net, inputq);
612
613 if (flags & TIPC_NAMED_MSG_EVT)
614 tipc_named_rcv(net, namedq);
cb1b7280
JPM
615
616 if (flags & TIPC_BCAST_MSG_EVT)
617 tipc_bclink_input(net);
9db9fdd1 618}
3e4b6ab5
RA
619
620/* Caller should hold node lock for the passed node */
d8182804 621static int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node)
3e4b6ab5
RA
622{
623 void *hdr;
624 struct nlattr *attrs;
625
626 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family,
627 NLM_F_MULTI, TIPC_NL_NODE_GET);
628 if (!hdr)
629 return -EMSGSIZE;
630
631 attrs = nla_nest_start(msg->skb, TIPC_NLA_NODE);
632 if (!attrs)
633 goto msg_full;
634
635 if (nla_put_u32(msg->skb, TIPC_NLA_NODE_ADDR, node->addr))
636 goto attr_msg_full;
637 if (tipc_node_is_up(node))
638 if (nla_put_flag(msg->skb, TIPC_NLA_NODE_UP))
639 goto attr_msg_full;
640
641 nla_nest_end(msg->skb, attrs);
642 genlmsg_end(msg->skb, hdr);
643
644 return 0;
645
646attr_msg_full:
647 nla_nest_cancel(msg->skb, attrs);
648msg_full:
649 genlmsg_cancel(msg->skb, hdr);
650
651 return -EMSGSIZE;
652}
653
654int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb)
655{
656 int err;
f2f9800d
YX
657 struct net *net = sock_net(skb->sk);
658 struct tipc_net *tn = net_generic(net, tipc_net_id);
3e4b6ab5
RA
659 int done = cb->args[0];
660 int last_addr = cb->args[1];
661 struct tipc_node *node;
662 struct tipc_nl_msg msg;
663
664 if (done)
665 return 0;
666
667 msg.skb = skb;
668 msg.portid = NETLINK_CB(cb->skb).portid;
669 msg.seq = cb->nlh->nlmsg_seq;
670
671 rcu_read_lock();
672
f2f9800d 673 if (last_addr && !tipc_node_find(net, last_addr)) {
3e4b6ab5
RA
674 rcu_read_unlock();
675 /* We never set seq or call nl_dump_check_consistent() this
676 * means that setting prev_seq here will cause the consistence
677 * check to fail in the netlink callback handler. Resulting in
678 * the NLMSG_DONE message having the NLM_F_DUMP_INTR flag set if
679 * the node state changed while we released the lock.
680 */
681 cb->prev_seq = 1;
682 return -EPIPE;
683 }
684
f2f9800d 685 list_for_each_entry_rcu(node, &tn->node_list, list) {
3e4b6ab5
RA
686 if (last_addr) {
687 if (node->addr == last_addr)
688 last_addr = 0;
689 else
690 continue;
691 }
692
693 tipc_node_lock(node);
694 err = __tipc_nl_add_node(&msg, node);
695 if (err) {
696 last_addr = node->addr;
697 tipc_node_unlock(node);
698 goto out;
699 }
700
701 tipc_node_unlock(node);
702 }
703 done = 1;
704out:
705 cb->args[0] = done;
706 cb->args[1] = last_addr;
707 rcu_read_unlock();
708
709 return skb->len;
710}