diff options
Diffstat (limited to 'net/tipc/server.c')
-rw-r--r-- | net/tipc/server.c | 121 |
1 files changed, 94 insertions, 27 deletions
diff --git a/net/tipc/server.c b/net/tipc/server.c index 3cd6402e812c..713077536d0c 100644 --- a/net/tipc/server.c +++ b/net/tipc/server.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include "server.h" | 36 | #include "server.h" |
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "socket.h" | 38 | #include "socket.h" |
39 | #include "addr.h" | ||
40 | #include "msg.h" | ||
39 | #include <net/sock.h> | 41 | #include <net/sock.h> |
40 | #include <linux/module.h> | 42 | #include <linux/module.h> |
41 | 43 | ||
@@ -105,13 +107,11 @@ static void tipc_conn_kref_release(struct kref *kref) | |||
105 | kernel_bind(sock, (struct sockaddr *)saddr, sizeof(*saddr)); | 107 | kernel_bind(sock, (struct sockaddr *)saddr, sizeof(*saddr)); |
106 | sock_release(sock); | 108 | sock_release(sock); |
107 | con->sock = NULL; | 109 | con->sock = NULL; |
108 | |||
109 | spin_lock_bh(&s->idr_lock); | ||
110 | idr_remove(&s->conn_idr, con->conid); | ||
111 | s->idr_in_use--; | ||
112 | spin_unlock_bh(&s->idr_lock); | ||
113 | } | 110 | } |
114 | 111 | spin_lock_bh(&s->idr_lock); | |
112 | idr_remove(&s->conn_idr, con->conid); | ||
113 | s->idr_in_use--; | ||
114 | spin_unlock_bh(&s->idr_lock); | ||
115 | tipc_clean_outqueues(con); | 115 | tipc_clean_outqueues(con); |
116 | kfree(con); | 116 | kfree(con); |
117 | } | 117 | } |
@@ -197,7 +197,8 @@ static void tipc_close_conn(struct tipc_conn *con) | |||
197 | struct tipc_server *s = con->server; | 197 | struct tipc_server *s = con->server; |
198 | 198 | ||
199 | if (test_and_clear_bit(CF_CONNECTED, &con->flags)) { | 199 | if (test_and_clear_bit(CF_CONNECTED, &con->flags)) { |
200 | tipc_unregister_callbacks(con); | 200 | if (con->sock) |
201 | tipc_unregister_callbacks(con); | ||
201 | 202 | ||
202 | if (con->conid) | 203 | if (con->conid) |
203 | s->tipc_conn_release(con->conid, con->usr_data); | 204 | s->tipc_conn_release(con->conid, con->usr_data); |
@@ -207,8 +208,8 @@ static void tipc_close_conn(struct tipc_conn *con) | |||
207 | * are harmless for us here as we have already deleted this | 208 | * are harmless for us here as we have already deleted this |
208 | * connection from server connection list. | 209 | * connection from server connection list. |
209 | */ | 210 | */ |
210 | kernel_sock_shutdown(con->sock, SHUT_RDWR); | 211 | if (con->sock) |
211 | 212 | kernel_sock_shutdown(con->sock, SHUT_RDWR); | |
212 | conn_put(con); | 213 | conn_put(con); |
213 | } | 214 | } |
214 | } | 215 | } |
@@ -487,38 +488,104 @@ void tipc_conn_terminate(struct tipc_server *s, int conid) | |||
487 | } | 488 | } |
488 | } | 489 | } |
489 | 490 | ||
491 | bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, | ||
492 | u32 lower, u32 upper, int *conid) | ||
493 | { | ||
494 | struct tipc_subscriber *scbr; | ||
495 | struct tipc_subscr sub; | ||
496 | struct tipc_server *s; | ||
497 | struct tipc_conn *con; | ||
498 | |||
499 | sub.seq.type = type; | ||
500 | sub.seq.lower = lower; | ||
501 | sub.seq.upper = upper; | ||
502 | sub.timeout = TIPC_WAIT_FOREVER; | ||
503 | sub.filter = TIPC_SUB_PORTS; | ||
504 | *(u32 *)&sub.usr_handle = port; | ||
505 | |||
506 | con = tipc_alloc_conn(tipc_topsrv(net)); | ||
507 | if (!con) | ||
508 | return false; | ||
509 | |||
510 | *conid = con->conid; | ||
511 | s = con->server; | ||
512 | scbr = s->tipc_conn_new(*conid); | ||
513 | if (!scbr) { | ||
514 | tipc_close_conn(con); | ||
515 | return false; | ||
516 | } | ||
517 | |||
518 | con->usr_data = scbr; | ||
519 | con->sock = NULL; | ||
520 | s->tipc_conn_recvmsg(net, *conid, NULL, scbr, &sub, sizeof(sub)); | ||
521 | return true; | ||
522 | } | ||
523 | |||
524 | void tipc_topsrv_kern_unsubscr(struct net *net, int conid) | ||
525 | { | ||
526 | struct tipc_conn *con; | ||
527 | |||
528 | con = tipc_conn_lookup(tipc_topsrv(net), conid); | ||
529 | if (!con) | ||
530 | return; | ||
531 | tipc_close_conn(con); | ||
532 | conn_put(con); | ||
533 | } | ||
534 | |||
535 | static void tipc_send_kern_top_evt(struct net *net, struct tipc_event *evt) | ||
536 | { | ||
537 | u32 port = *(u32 *)&evt->s.usr_handle; | ||
538 | u32 self = tipc_own_addr(net); | ||
539 | struct sk_buff_head evtq; | ||
540 | struct sk_buff *skb; | ||
541 | |||
542 | skb = tipc_msg_create(TOP_SRV, 0, INT_H_SIZE, sizeof(*evt), | ||
543 | self, self, port, port, 0); | ||
544 | if (!skb) | ||
545 | return; | ||
546 | msg_set_dest_droppable(buf_msg(skb), true); | ||
547 | memcpy(msg_data(buf_msg(skb)), evt, sizeof(*evt)); | ||
548 | skb_queue_head_init(&evtq); | ||
549 | __skb_queue_tail(&evtq, skb); | ||
550 | tipc_sk_rcv(net, &evtq); | ||
551 | } | ||
552 | |||
490 | static void tipc_send_to_sock(struct tipc_conn *con) | 553 | static void tipc_send_to_sock(struct tipc_conn *con) |
491 | { | 554 | { |
492 | int count = 0; | ||
493 | struct tipc_server *s = con->server; | 555 | struct tipc_server *s = con->server; |
494 | struct outqueue_entry *e; | 556 | struct outqueue_entry *e; |
557 | struct tipc_event *evt; | ||
495 | struct msghdr msg; | 558 | struct msghdr msg; |
559 | int count = 0; | ||
496 | int ret; | 560 | int ret; |
497 | 561 | ||
498 | spin_lock_bh(&con->outqueue_lock); | 562 | spin_lock_bh(&con->outqueue_lock); |
499 | while (test_bit(CF_CONNECTED, &con->flags)) { | 563 | while (test_bit(CF_CONNECTED, &con->flags)) { |
500 | e = list_entry(con->outqueue.next, struct outqueue_entry, | 564 | e = list_entry(con->outqueue.next, struct outqueue_entry, list); |
501 | list); | ||
502 | if ((struct list_head *) e == &con->outqueue) | 565 | if ((struct list_head *) e == &con->outqueue) |
503 | break; | 566 | break; |
504 | spin_unlock_bh(&con->outqueue_lock); | ||
505 | 567 | ||
506 | memset(&msg, 0, sizeof(msg)); | 568 | spin_unlock_bh(&con->outqueue_lock); |
507 | msg.msg_flags = MSG_DONTWAIT; | ||
508 | 569 | ||
509 | if (s->type == SOCK_DGRAM || s->type == SOCK_RDM) { | 570 | if (con->sock) { |
510 | msg.msg_name = &e->dest; | 571 | memset(&msg, 0, sizeof(msg)); |
511 | msg.msg_namelen = sizeof(struct sockaddr_tipc); | 572 | msg.msg_flags = MSG_DONTWAIT; |
512 | } | 573 | if (s->type == SOCK_DGRAM || s->type == SOCK_RDM) { |
513 | ret = kernel_sendmsg(con->sock, &msg, &e->iov, 1, | 574 | msg.msg_name = &e->dest; |
514 | e->iov.iov_len); | 575 | msg.msg_namelen = sizeof(struct sockaddr_tipc); |
515 | if (ret == -EWOULDBLOCK || ret == 0) { | 576 | } |
516 | cond_resched(); | 577 | ret = kernel_sendmsg(con->sock, &msg, &e->iov, 1, |
517 | goto out; | 578 | e->iov.iov_len); |
518 | } else if (ret < 0) { | 579 | if (ret == -EWOULDBLOCK || ret == 0) { |
519 | goto send_err; | 580 | cond_resched(); |
581 | goto out; | ||
582 | } else if (ret < 0) { | ||
583 | goto send_err; | ||
584 | } | ||
585 | } else { | ||
586 | evt = e->iov.iov_base; | ||
587 | tipc_send_kern_top_evt(s->net, evt); | ||
520 | } | 588 | } |
521 | |||
522 | /* Don't starve users filling buffers */ | 589 | /* Don't starve users filling buffers */ |
523 | if (++count >= MAX_SEND_MSG_COUNT) { | 590 | if (++count >= MAX_SEND_MSG_COUNT) { |
524 | cond_resched(); | 591 | cond_resched(); |