diff options
Diffstat (limited to 'net/tipc/node.c')
-rw-r--r-- | net/tipc/node.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/net/tipc/node.c b/net/tipc/node.c index 6ea2c15cfc88..17e6378c4dfe 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c | |||
@@ -51,6 +51,13 @@ static u32 tipc_num_nodes; | |||
51 | static u32 tipc_num_links; | 51 | static u32 tipc_num_links; |
52 | static DEFINE_SPINLOCK(node_list_lock); | 52 | static DEFINE_SPINLOCK(node_list_lock); |
53 | 53 | ||
54 | struct tipc_sock_conn { | ||
55 | u32 port; | ||
56 | u32 peer_port; | ||
57 | u32 peer_node; | ||
58 | struct list_head list; | ||
59 | }; | ||
60 | |||
54 | /* | 61 | /* |
55 | * 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 |
56 | * 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 |
@@ -101,6 +108,7 @@ struct tipc_node *tipc_node_create(u32 addr) | |||
101 | INIT_HLIST_NODE(&n_ptr->hash); | 108 | INIT_HLIST_NODE(&n_ptr->hash); |
102 | INIT_LIST_HEAD(&n_ptr->list); | 109 | INIT_LIST_HEAD(&n_ptr->list); |
103 | INIT_LIST_HEAD(&n_ptr->nsub); | 110 | INIT_LIST_HEAD(&n_ptr->nsub); |
111 | INIT_LIST_HEAD(&n_ptr->conn_sks); | ||
104 | __skb_queue_head_init(&n_ptr->waiting_sks); | 112 | __skb_queue_head_init(&n_ptr->waiting_sks); |
105 | 113 | ||
106 | 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)]); |
@@ -138,6 +146,71 @@ void tipc_node_stop(void) | |||
138 | spin_unlock_bh(&node_list_lock); | 146 | spin_unlock_bh(&node_list_lock); |
139 | } | 147 | } |
140 | 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 | |||
141 | /** | 214 | /** |
142 | * tipc_node_link_up - handle addition of link | 215 | * tipc_node_link_up - handle addition of link |
143 | * | 216 | * |
@@ -476,6 +549,7 @@ int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len) | |||
476 | void tipc_node_unlock(struct tipc_node *node) | 549 | void tipc_node_unlock(struct tipc_node *node) |
477 | { | 550 | { |
478 | LIST_HEAD(nsub_list); | 551 | LIST_HEAD(nsub_list); |
552 | LIST_HEAD(conn_sks); | ||
479 | struct sk_buff_head waiting_sks; | 553 | struct sk_buff_head waiting_sks; |
480 | u32 addr = 0; | 554 | u32 addr = 0; |
481 | 555 | ||
@@ -491,6 +565,7 @@ void tipc_node_unlock(struct tipc_node *node) | |||
491 | } | 565 | } |
492 | if (node->action_flags & TIPC_NOTIFY_NODE_DOWN) { | 566 | if (node->action_flags & TIPC_NOTIFY_NODE_DOWN) { |
493 | list_replace_init(&node->nsub, &nsub_list); | 567 | list_replace_init(&node->nsub, &nsub_list); |
568 | list_replace_init(&node->conn_sks, &conn_sks); | ||
494 | node->action_flags &= ~TIPC_NOTIFY_NODE_DOWN; | 569 | node->action_flags &= ~TIPC_NOTIFY_NODE_DOWN; |
495 | } | 570 | } |
496 | if (node->action_flags & TIPC_NOTIFY_NODE_UP) { | 571 | if (node->action_flags & TIPC_NOTIFY_NODE_UP) { |
@@ -502,6 +577,9 @@ void tipc_node_unlock(struct tipc_node *node) | |||
502 | while (!skb_queue_empty(&waiting_sks)) | 577 | while (!skb_queue_empty(&waiting_sks)) |
503 | tipc_sk_rcv(__skb_dequeue(&waiting_sks)); | 578 | tipc_sk_rcv(__skb_dequeue(&waiting_sks)); |
504 | 579 | ||
580 | if (!list_empty(&conn_sks)) | ||
581 | tipc_node_abort_sock_conns(&conn_sks); | ||
582 | |||
505 | if (!list_empty(&nsub_list)) | 583 | if (!list_empty(&nsub_list)) |
506 | tipc_nodesub_notify(&nsub_list); | 584 | tipc_nodesub_notify(&nsub_list); |
507 | 585 | ||