diff options
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r-- | net/tipc/socket.c | 51 |
1 files changed, 39 insertions, 12 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 686a11be5c58..f2be4c2e20bb 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -63,6 +63,9 @@ static const struct proto_ops msg_ops; | |||
63 | static struct proto tipc_proto; | 63 | static struct proto tipc_proto; |
64 | static struct proto tipc_proto_kern; | 64 | static struct proto tipc_proto_kern; |
65 | 65 | ||
66 | DEFINE_SPINLOCK(tipc_port_list_lock); | ||
67 | LIST_HEAD(tipc_socks); | ||
68 | |||
66 | /* | 69 | /* |
67 | * Revised TIPC socket locking policy: | 70 | * Revised TIPC socket locking policy: |
68 | * | 71 | * |
@@ -156,6 +159,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock, | |||
156 | struct sock *sk; | 159 | struct sock *sk; |
157 | struct tipc_sock *tsk; | 160 | struct tipc_sock *tsk; |
158 | struct tipc_port *port; | 161 | struct tipc_port *port; |
162 | struct tipc_msg *msg; | ||
159 | u32 ref; | 163 | u32 ref; |
160 | 164 | ||
161 | /* Validate arguments */ | 165 | /* Validate arguments */ |
@@ -191,18 +195,28 @@ static int tipc_sk_create(struct net *net, struct socket *sock, | |||
191 | 195 | ||
192 | tsk = tipc_sk(sk); | 196 | tsk = tipc_sk(sk); |
193 | port = &tsk->port; | 197 | port = &tsk->port; |
194 | 198 | ref = tipc_ref_acquire(port, &port->lock); | |
195 | ref = tipc_port_init(port, TIPC_LOW_IMPORTANCE); | ||
196 | if (!ref) { | 199 | if (!ref) { |
197 | pr_warn("Socket registration failed, ref. table exhausted\n"); | 200 | pr_warn("Socket create failed; reference table exhausted\n"); |
198 | sk_free(sk); | ||
199 | return -ENOMEM; | 201 | return -ENOMEM; |
200 | } | 202 | } |
203 | port->max_pkt = MAX_PKT_DEFAULT; | ||
204 | port->ref = ref; | ||
205 | INIT_LIST_HEAD(&port->publications); | ||
206 | INIT_LIST_HEAD(&port->port_list); | ||
207 | |||
208 | /* Guard against race during node address update */ | ||
209 | spin_lock_bh(&tipc_port_list_lock); | ||
210 | msg = &port->phdr; | ||
211 | tipc_msg_init(msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG, | ||
212 | NAMED_H_SIZE, 0); | ||
213 | msg_set_origport(msg, ref); | ||
214 | list_add_tail(&port->port_list, &tipc_socks); | ||
215 | spin_unlock_bh(&tipc_port_list_lock); | ||
201 | 216 | ||
202 | /* Finish initializing socket data structures */ | 217 | /* Finish initializing socket data structures */ |
203 | sock->ops = ops; | 218 | sock->ops = ops; |
204 | sock->state = state; | 219 | sock->state = state; |
205 | |||
206 | sock_init_data(sock, sk); | 220 | sock_init_data(sock, sk); |
207 | k_init_timer(&port->timer, (Handler)tipc_sk_timeout, ref); | 221 | k_init_timer(&port->timer, (Handler)tipc_sk_timeout, ref); |
208 | sk->sk_backlog_rcv = tipc_backlog_rcv; | 222 | sk->sk_backlog_rcv = tipc_backlog_rcv; |
@@ -330,6 +344,7 @@ static int tipc_release(struct socket *sock) | |||
330 | * Reject all unreceived messages, except on an active connection | 344 | * Reject all unreceived messages, except on an active connection |
331 | * (which disconnects locally & sends a 'FIN+' to peer) | 345 | * (which disconnects locally & sends a 'FIN+' to peer) |
332 | */ | 346 | */ |
347 | dnode = tipc_port_peernode(port); | ||
333 | while (sock->state != SS_DISCONNECTING) { | 348 | while (sock->state != SS_DISCONNECTING) { |
334 | buf = __skb_dequeue(&sk->sk_receive_queue); | 349 | buf = __skb_dequeue(&sk->sk_receive_queue); |
335 | if (buf == NULL) | 350 | if (buf == NULL) |
@@ -341,18 +356,31 @@ static int tipc_release(struct socket *sock) | |||
341 | (sock->state == SS_CONNECTED)) { | 356 | (sock->state == SS_CONNECTED)) { |
342 | sock->state = SS_DISCONNECTING; | 357 | sock->state = SS_DISCONNECTING; |
343 | port->connected = 0; | 358 | port->connected = 0; |
344 | tipc_node_remove_conn(tipc_port_peernode(port), | 359 | tipc_node_remove_conn(dnode, port->ref); |
345 | port->ref); | ||
346 | } | 360 | } |
347 | if (tipc_msg_reverse(buf, &dnode, TIPC_ERR_NO_PORT)) | 361 | if (tipc_msg_reverse(buf, &dnode, TIPC_ERR_NO_PORT)) |
348 | tipc_link_xmit(buf, dnode, 0); | 362 | tipc_link_xmit(buf, dnode, 0); |
349 | } | 363 | } |
350 | } | 364 | } |
351 | 365 | ||
352 | /* Destroy TIPC port; also disconnects an active connection and | 366 | tipc_withdraw(port, 0, NULL); |
353 | * sends a 'FIN-' to peer. | 367 | spin_lock_bh(port->lock); |
354 | */ | 368 | tipc_ref_discard(port->ref); |
355 | tipc_port_destroy(port); | 369 | spin_unlock_bh(port->lock); |
370 | k_cancel_timer(&port->timer); | ||
371 | if (port->connected) { | ||
372 | buf = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG, | ||
373 | SHORT_H_SIZE, 0, dnode, tipc_own_addr, | ||
374 | tipc_port_peerport(port), | ||
375 | port->ref, TIPC_ERR_NO_PORT); | ||
376 | if (buf) | ||
377 | tipc_link_xmit(buf, dnode, port->ref); | ||
378 | tipc_node_remove_conn(dnode, port->ref); | ||
379 | } | ||
380 | spin_lock_bh(&tipc_port_list_lock); | ||
381 | list_del(&port->port_list); | ||
382 | spin_unlock_bh(&tipc_port_list_lock); | ||
383 | k_term_timer(&port->timer); | ||
356 | 384 | ||
357 | /* Discard any remaining (connection-based) messages in receive queue */ | 385 | /* Discard any remaining (connection-based) messages in receive queue */ |
358 | __skb_queue_purge(&sk->sk_receive_queue); | 386 | __skb_queue_purge(&sk->sk_receive_queue); |
@@ -360,7 +388,6 @@ static int tipc_release(struct socket *sock) | |||
360 | /* Reject any messages that accumulated in backlog queue */ | 388 | /* Reject any messages that accumulated in backlog queue */ |
361 | sock->state = SS_DISCONNECTING; | 389 | sock->state = SS_DISCONNECTING; |
362 | release_sock(sk); | 390 | release_sock(sk); |
363 | |||
364 | sock_put(sk); | 391 | sock_put(sk); |
365 | sock->sk = NULL; | 392 | sock->sk = NULL; |
366 | 393 | ||