diff options
Diffstat (limited to 'net/tipc/node.c')
| -rw-r--r-- | net/tipc/node.c | 131 |
1 files changed, 118 insertions, 13 deletions
diff --git a/net/tipc/node.c b/net/tipc/node.c index f7069299943f..5781634e957d 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include "config.h" | 38 | #include "config.h" |
| 39 | #include "node.h" | 39 | #include "node.h" |
| 40 | #include "name_distr.h" | 40 | #include "name_distr.h" |
| 41 | #include "socket.h" | ||
| 41 | 42 | ||
| 42 | #define NODE_HTABLE_SIZE 512 | 43 | #define NODE_HTABLE_SIZE 512 |
| 43 | 44 | ||
| @@ -50,6 +51,13 @@ static u32 tipc_num_nodes; | |||
| 50 | static u32 tipc_num_links; | 51 | static u32 tipc_num_links; |
| 51 | static DEFINE_SPINLOCK(node_list_lock); | 52 | static DEFINE_SPINLOCK(node_list_lock); |
| 52 | 53 | ||
| 54 | struct tipc_sock_conn { | ||
| 55 | u32 port; | ||
| 56 | u32 peer_port; | ||
| 57 | u32 peer_node; | ||
| 58 | struct list_head list; | ||
| 59 | }; | ||
| 60 | |||
| 53 | /* | 61 | /* |
| 54 | * A trivial power-of-two bitmask technique is used for speed, since this | 62 | * A trivial power-of-two bitmask technique is used for speed, since this |
| 55 | * operation is done for every incoming TIPC packet. The number of hash table | 63 | * operation is done for every incoming TIPC packet. The number of hash table |
| @@ -100,6 +108,8 @@ struct tipc_node *tipc_node_create(u32 addr) | |||
| 100 | INIT_HLIST_NODE(&n_ptr->hash); | 108 | INIT_HLIST_NODE(&n_ptr->hash); |
| 101 | INIT_LIST_HEAD(&n_ptr->list); | 109 | INIT_LIST_HEAD(&n_ptr->list); |
| 102 | INIT_LIST_HEAD(&n_ptr->nsub); | 110 | INIT_LIST_HEAD(&n_ptr->nsub); |
| 111 | INIT_LIST_HEAD(&n_ptr->conn_sks); | ||
| 112 | __skb_queue_head_init(&n_ptr->waiting_sks); | ||
| 103 | 113 | ||
| 104 | hlist_add_head_rcu(&n_ptr->hash, &node_htable[tipc_hashfn(addr)]); | 114 | hlist_add_head_rcu(&n_ptr->hash, &node_htable[tipc_hashfn(addr)]); |
| 105 | 115 | ||
| @@ -136,6 +146,71 @@ void tipc_node_stop(void) | |||
| 136 | spin_unlock_bh(&node_list_lock); | 146 | spin_unlock_bh(&node_list_lock); |
| 137 | } | 147 | } |
| 138 | 148 | ||
| 149 | int tipc_node_add_conn(u32 dnode, u32 port, u32 peer_port) | ||
| 150 | { | ||
| 151 | struct tipc_node *node; | ||
| 152 | struct tipc_sock_conn *conn; | ||
| 153 | |||
| 154 | if (in_own_node(dnode)) | ||
| 155 | return 0; | ||
| 156 | |||
| 157 | node = tipc_node_find(dnode); | ||
| 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 | |||
| 175 | void tipc_node_remove_conn(u32 dnode, u32 port) | ||
| 176 | { | ||
| 177 | struct tipc_node *node; | ||
| 178 | struct tipc_sock_conn *conn, *safe; | ||
| 179 | |||
| 180 | if (in_own_node(dnode)) | ||
| 181 | return; | ||
| 182 | |||
| 183 | node = tipc_node_find(dnode); | ||
| 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 | |||
| 197 | void tipc_node_abort_sock_conns(struct list_head *conns) | ||
| 198 | { | ||
| 199 | struct tipc_sock_conn *conn, *safe; | ||
| 200 | struct sk_buff *buf; | ||
| 201 | |||
| 202 | list_for_each_entry_safe(conn, safe, conns, list) { | ||
| 203 | buf = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG, | ||
| 204 | SHORT_H_SIZE, 0, tipc_own_addr, | ||
| 205 | conn->peer_node, conn->port, | ||
| 206 | conn->peer_port, TIPC_ERR_NO_NODE); | ||
| 207 | if (likely(buf)) | ||
| 208 | tipc_sk_rcv(buf); | ||
| 209 | list_del(&conn->list); | ||
| 210 | kfree(conn); | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 139 | /** | 214 | /** |
| 140 | * tipc_node_link_up - handle addition of link | 215 | * tipc_node_link_up - handle addition of link |
| 141 | * | 216 | * |
| @@ -144,11 +219,11 @@ void tipc_node_stop(void) | |||
| 144 | void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr) | 219 | void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr) |
| 145 | { | 220 | { |
| 146 | struct tipc_link **active = &n_ptr->active_links[0]; | 221 | struct tipc_link **active = &n_ptr->active_links[0]; |
| 147 | u32 addr = n_ptr->addr; | ||
| 148 | 222 | ||
| 149 | n_ptr->working_links++; | 223 | n_ptr->working_links++; |
| 150 | tipc_nametbl_publish(TIPC_LINK_STATE, addr, addr, TIPC_NODE_SCOPE, | 224 | n_ptr->action_flags |= TIPC_NOTIFY_LINK_UP; |
| 151 | l_ptr->bearer_id, addr); | 225 | n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id; |
| 226 | |||
| 152 | pr_info("Established link <%s> on network plane %c\n", | 227 | pr_info("Established link <%s> on network plane %c\n", |
| 153 | l_ptr->name, l_ptr->net_plane); | 228 | l_ptr->name, l_ptr->net_plane); |
| 154 | 229 | ||
| @@ -209,10 +284,10 @@ static void node_select_active_links(struct tipc_node *n_ptr) | |||
| 209 | void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr) | 284 | void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr) |
| 210 | { | 285 | { |
| 211 | struct tipc_link **active; | 286 | struct tipc_link **active; |
| 212 | u32 addr = n_ptr->addr; | ||
| 213 | 287 | ||
| 214 | n_ptr->working_links--; | 288 | n_ptr->working_links--; |
| 215 | tipc_nametbl_withdraw(TIPC_LINK_STATE, addr, l_ptr->bearer_id, addr); | 289 | n_ptr->action_flags |= TIPC_NOTIFY_LINK_DOWN; |
| 290 | n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id; | ||
| 216 | 291 | ||
| 217 | if (!tipc_link_is_active(l_ptr)) { | 292 | if (!tipc_link_is_active(l_ptr)) { |
| 218 | pr_info("Lost standby link <%s> on network plane %c\n", | 293 | pr_info("Lost standby link <%s> on network plane %c\n", |
| @@ -474,25 +549,55 @@ int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len) | |||
| 474 | void tipc_node_unlock(struct tipc_node *node) | 549 | void tipc_node_unlock(struct tipc_node *node) |
| 475 | { | 550 | { |
| 476 | LIST_HEAD(nsub_list); | 551 | LIST_HEAD(nsub_list); |
| 552 | LIST_HEAD(conn_sks); | ||
| 553 | struct sk_buff_head waiting_sks; | ||
| 477 | u32 addr = 0; | 554 | u32 addr = 0; |
| 555 | int flags = node->action_flags; | ||
| 556 | u32 link_id = 0; | ||
| 478 | 557 | ||
| 479 | if (likely(!node->action_flags)) { | 558 | if (likely(!flags)) { |
| 480 | spin_unlock_bh(&node->lock); | 559 | spin_unlock_bh(&node->lock); |
| 481 | return; | 560 | return; |
| 482 | } | 561 | } |
| 483 | 562 | ||
| 484 | if (node->action_flags & TIPC_NOTIFY_NODE_DOWN) { | 563 | addr = node->addr; |
| 564 | link_id = node->link_id; | ||
| 565 | __skb_queue_head_init(&waiting_sks); | ||
| 566 | |||
| 567 | if (flags & TIPC_WAKEUP_USERS) | ||
| 568 | skb_queue_splice_init(&node->waiting_sks, &waiting_sks); | ||
| 569 | |||
| 570 | if (flags & TIPC_NOTIFY_NODE_DOWN) { | ||
| 485 | list_replace_init(&node->nsub, &nsub_list); | 571 | list_replace_init(&node->nsub, &nsub_list); |
| 486 | node->action_flags &= ~TIPC_NOTIFY_NODE_DOWN; | 572 | list_replace_init(&node->conn_sks, &conn_sks); |
| 487 | } | ||
| 488 | if (node->action_flags & TIPC_NOTIFY_NODE_UP) { | ||
| 489 | node->action_flags &= ~TIPC_NOTIFY_NODE_UP; | ||
| 490 | addr = node->addr; | ||
| 491 | } | 573 | } |
| 574 | node->action_flags &= ~(TIPC_WAKEUP_USERS | TIPC_NOTIFY_NODE_DOWN | | ||
| 575 | TIPC_NOTIFY_NODE_UP | TIPC_NOTIFY_LINK_UP | | ||
| 576 | TIPC_NOTIFY_LINK_DOWN | | ||
| 577 | TIPC_WAKEUP_BCAST_USERS); | ||
| 578 | |||
| 492 | spin_unlock_bh(&node->lock); | 579 | spin_unlock_bh(&node->lock); |
| 493 | 580 | ||
| 581 | while (!skb_queue_empty(&waiting_sks)) | ||
| 582 | tipc_sk_rcv(__skb_dequeue(&waiting_sks)); | ||
| 583 | |||
| 584 | if (!list_empty(&conn_sks)) | ||
| 585 | tipc_node_abort_sock_conns(&conn_sks); | ||
| 586 | |||
| 494 | if (!list_empty(&nsub_list)) | 587 | if (!list_empty(&nsub_list)) |
| 495 | tipc_nodesub_notify(&nsub_list); | 588 | tipc_nodesub_notify(&nsub_list); |
| 496 | if (addr) | 589 | |
| 590 | if (flags & TIPC_WAKEUP_BCAST_USERS) | ||
| 591 | tipc_bclink_wakeup_users(); | ||
| 592 | |||
| 593 | if (flags & TIPC_NOTIFY_NODE_UP) | ||
| 497 | tipc_named_node_up(addr); | 594 | tipc_named_node_up(addr); |
| 595 | |||
| 596 | if (flags & TIPC_NOTIFY_LINK_UP) | ||
| 597 | tipc_nametbl_publish(TIPC_LINK_STATE, addr, addr, | ||
| 598 | TIPC_NODE_SCOPE, link_id, addr); | ||
| 599 | |||
| 600 | if (flags & TIPC_NOTIFY_LINK_DOWN) | ||
| 601 | tipc_nametbl_withdraw(TIPC_LINK_STATE, addr, | ||
| 602 | link_id, addr); | ||
| 498 | } | 603 | } |
