diff options
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/core.h | 5 | ||||
-rw-r--r-- | net/tipc/msg.h | 1 | ||||
-rw-r--r-- | net/tipc/server.c | 121 | ||||
-rw-r--r-- | net/tipc/server.h | 5 | ||||
-rw-r--r-- | net/tipc/socket.c | 32 |
5 files changed, 124 insertions, 40 deletions
diff --git a/net/tipc/core.h b/net/tipc/core.h index 5cc5398be722..964342689f2c 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h | |||
@@ -132,6 +132,11 @@ static inline struct list_head *tipc_nodes(struct net *net) | |||
132 | return &tipc_net(net)->node_list; | 132 | return &tipc_net(net)->node_list; |
133 | } | 133 | } |
134 | 134 | ||
135 | static inline struct tipc_server *tipc_topsrv(struct net *net) | ||
136 | { | ||
137 | return tipc_net(net)->topsrv; | ||
138 | } | ||
139 | |||
135 | static inline unsigned int tipc_hashfn(u32 addr) | 140 | static inline unsigned int tipc_hashfn(u32 addr) |
136 | { | 141 | { |
137 | return addr & (NODE_HTABLE_SIZE - 1); | 142 | return addr & (NODE_HTABLE_SIZE - 1); |
diff --git a/net/tipc/msg.h b/net/tipc/msg.h index c843fd2bc48d..d058b1c464e9 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h | |||
@@ -78,6 +78,7 @@ struct plist; | |||
78 | #define MSG_FRAGMENTER 12 | 78 | #define MSG_FRAGMENTER 12 |
79 | #define LINK_CONFIG 13 | 79 | #define LINK_CONFIG 13 |
80 | #define SOCK_WAKEUP 14 /* pseudo user */ | 80 | #define SOCK_WAKEUP 14 /* pseudo user */ |
81 | #define TOP_SRV 15 /* pseudo user */ | ||
81 | 82 | ||
82 | /* | 83 | /* |
83 | * Message header sizes | 84 | * Message header sizes |
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(); |
diff --git a/net/tipc/server.h b/net/tipc/server.h index 34f8055afa3b..2113c9192633 100644 --- a/net/tipc/server.h +++ b/net/tipc/server.h | |||
@@ -83,13 +83,16 @@ struct tipc_server { | |||
83 | int tipc_conn_sendmsg(struct tipc_server *s, int conid, | 83 | int tipc_conn_sendmsg(struct tipc_server *s, int conid, |
84 | struct sockaddr_tipc *addr, void *data, size_t len); | 84 | struct sockaddr_tipc *addr, void *data, size_t len); |
85 | 85 | ||
86 | bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, | ||
87 | u32 lower, u32 upper, int *conid); | ||
88 | void tipc_topsrv_kern_unsubscr(struct net *net, int conid); | ||
89 | |||
86 | /** | 90 | /** |
87 | * tipc_conn_terminate - terminate connection with server | 91 | * tipc_conn_terminate - terminate connection with server |
88 | * | 92 | * |
89 | * Note: Must call it in process context since it might sleep | 93 | * Note: Must call it in process context since it might sleep |
90 | */ | 94 | */ |
91 | void tipc_conn_terminate(struct tipc_server *s, int conid); | 95 | void tipc_conn_terminate(struct tipc_server *s, int conid); |
92 | |||
93 | int tipc_server_start(struct tipc_server *s); | 96 | int tipc_server_start(struct tipc_server *s); |
94 | 97 | ||
95 | void tipc_server_stop(struct tipc_server *s); | 98 | void tipc_server_stop(struct tipc_server *s); |
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index d50edd6e0019..9a7e7b5cf23f 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -896,6 +896,10 @@ exit: | |||
896 | kfree_skb(skb); | 896 | kfree_skb(skb); |
897 | } | 897 | } |
898 | 898 | ||
899 | static void tipc_sk_top_evt(struct tipc_sock *tsk, struct tipc_event *evt) | ||
900 | { | ||
901 | } | ||
902 | |||
899 | /** | 903 | /** |
900 | * tipc_sendmsg - send message in connectionless manner | 904 | * tipc_sendmsg - send message in connectionless manner |
901 | * @sock: socket structure | 905 | * @sock: socket structure |
@@ -1671,20 +1675,24 @@ static bool filter_rcv(struct sock *sk, struct sk_buff *skb, | |||
1671 | struct tipc_msg *hdr = buf_msg(skb); | 1675 | struct tipc_msg *hdr = buf_msg(skb); |
1672 | unsigned int limit = rcvbuf_limit(sk, skb); | 1676 | unsigned int limit = rcvbuf_limit(sk, skb); |
1673 | int err = TIPC_OK; | 1677 | int err = TIPC_OK; |
1674 | int usr = msg_user(hdr); | ||
1675 | u32 onode; | ||
1676 | |||
1677 | if (unlikely(msg_user(hdr) == CONN_MANAGER)) { | ||
1678 | tipc_sk_proto_rcv(tsk, skb, xmitq); | ||
1679 | return false; | ||
1680 | } | ||
1681 | 1678 | ||
1682 | if (unlikely(usr == SOCK_WAKEUP)) { | 1679 | if (unlikely(!msg_isdata(hdr))) { |
1683 | onode = msg_orignode(hdr); | 1680 | switch (msg_user(hdr)) { |
1681 | case CONN_MANAGER: | ||
1682 | tipc_sk_proto_rcv(tsk, skb, xmitq); | ||
1683 | return false; | ||
1684 | case SOCK_WAKEUP: | ||
1685 | u32_del(&tsk->cong_links, msg_orignode(hdr)); | ||
1686 | tsk->cong_link_cnt--; | ||
1687 | sk->sk_write_space(sk); | ||
1688 | break; | ||
1689 | case TOP_SRV: | ||
1690 | tipc_sk_top_evt(tsk, (void *)msg_data(hdr)); | ||
1691 | break; | ||
1692 | default: | ||
1693 | break; | ||
1694 | } | ||
1684 | kfree_skb(skb); | 1695 | kfree_skb(skb); |
1685 | u32_del(&tsk->cong_links, onode); | ||
1686 | tsk->cong_link_cnt--; | ||
1687 | sk->sk_write_space(sk); | ||
1688 | return false; | 1696 | return false; |
1689 | } | 1697 | } |
1690 | 1698 | ||