aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc')
-rw-r--r--net/tipc/name_table.c6
-rw-r--r--net/tipc/name_table.h3
-rw-r--r--net/tipc/server.c70
-rw-r--r--net/tipc/server.h6
-rw-r--r--net/tipc/socket.c4
-rw-r--r--net/tipc/subscr.c21
6 files changed, 56 insertions, 54 deletions
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index 64cdd3c302b0..ed0457cc99d6 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -680,8 +680,7 @@ exit:
680 * - Determines if any node local ports overlap 680 * - Determines if any node local ports overlap
681 */ 681 */
682void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower, 682void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower,
683 u32 upper, u32 scope, 683 u32 upper, struct tipc_nlist *nodes)
684 struct tipc_nlist *nodes)
685{ 684{
686 struct sub_seq *sseq, *stop; 685 struct sub_seq *sseq, *stop;
687 struct publication *publ; 686 struct publication *publ;
@@ -699,8 +698,7 @@ void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower,
699 for (; sseq != stop && sseq->lower <= upper; sseq++) { 698 for (; sseq != stop && sseq->lower <= upper; sseq++) {
700 info = sseq->info; 699 info = sseq->info;
701 list_for_each_entry(publ, &info->zone_list, zone_list) { 700 list_for_each_entry(publ, &info->zone_list, zone_list) {
702 if (publ->scope == scope) 701 tipc_nlist_add(nodes, publ->node);
703 tipc_nlist_add(nodes, publ->node);
704 } 702 }
705 } 703 }
706 spin_unlock_bh(&seq->lock); 704 spin_unlock_bh(&seq->lock);
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h
index b595d8aa00f0..f56e7cb3d436 100644
--- a/net/tipc/name_table.h
+++ b/net/tipc/name_table.h
@@ -105,8 +105,7 @@ int tipc_nametbl_mc_lookup(struct net *net, u32 type, u32 lower, u32 upper,
105void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp, 105void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp,
106 u32 type, u32 domain); 106 u32 type, u32 domain);
107void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower, 107void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower,
108 u32 upper, u32 domain, 108 u32 upper, struct tipc_nlist *nodes);
109 struct tipc_nlist *nodes);
110bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 domain, 109bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 domain,
111 struct list_head *dsts, int *dstcnt, u32 exclude, 110 struct list_head *dsts, int *dstcnt, u32 exclude,
112 bool all); 111 bool all);
diff --git a/net/tipc/server.c b/net/tipc/server.c
index 8ee5e86b7870..c0d331f13eee 100644
--- a/net/tipc/server.c
+++ b/net/tipc/server.c
@@ -132,10 +132,11 @@ static struct tipc_conn *tipc_conn_lookup(struct tipc_server *s, int conid)
132 132
133 spin_lock_bh(&s->idr_lock); 133 spin_lock_bh(&s->idr_lock);
134 con = idr_find(&s->conn_idr, conid); 134 con = idr_find(&s->conn_idr, conid);
135 if (con && test_bit(CF_CONNECTED, &con->flags)) 135 if (con) {
136 conn_get(con); 136 if (!test_bit(CF_CONNECTED, &con->flags) ||
137 else 137 !kref_get_unless_zero(&con->kref))
138 con = NULL; 138 con = NULL;
139 }
139 spin_unlock_bh(&s->idr_lock); 140 spin_unlock_bh(&s->idr_lock);
140 return con; 141 return con;
141} 142}
@@ -183,35 +184,28 @@ static void tipc_register_callbacks(struct socket *sock, struct tipc_conn *con)
183 write_unlock_bh(&sk->sk_callback_lock); 184 write_unlock_bh(&sk->sk_callback_lock);
184} 185}
185 186
186static void tipc_unregister_callbacks(struct tipc_conn *con)
187{
188 struct sock *sk = con->sock->sk;
189
190 write_lock_bh(&sk->sk_callback_lock);
191 sk->sk_user_data = NULL;
192 write_unlock_bh(&sk->sk_callback_lock);
193}
194
195static void tipc_close_conn(struct tipc_conn *con) 187static void tipc_close_conn(struct tipc_conn *con)
196{ 188{
197 struct tipc_server *s = con->server; 189 struct tipc_server *s = con->server;
190 struct sock *sk = con->sock->sk;
191 bool disconnect = false;
198 192
199 if (test_and_clear_bit(CF_CONNECTED, &con->flags)) { 193 write_lock_bh(&sk->sk_callback_lock);
200 if (con->sock) 194 disconnect = test_and_clear_bit(CF_CONNECTED, &con->flags);
201 tipc_unregister_callbacks(con); 195 if (disconnect) {
202 196 sk->sk_user_data = NULL;
203 if (con->conid) 197 if (con->conid)
204 s->tipc_conn_release(con->conid, con->usr_data); 198 s->tipc_conn_release(con->conid, con->usr_data);
205
206 /* We shouldn't flush pending works as we may be in the
207 * thread. In fact the races with pending rx/tx work structs
208 * are harmless for us here as we have already deleted this
209 * connection from server connection list.
210 */
211 if (con->sock)
212 kernel_sock_shutdown(con->sock, SHUT_RDWR);
213 conn_put(con);
214 } 199 }
200 write_unlock_bh(&sk->sk_callback_lock);
201
202 /* Handle concurrent calls from sending and receiving threads */
203 if (!disconnect)
204 return;
205
206 /* Don't flush pending works, -just let them expire */
207 kernel_sock_shutdown(con->sock, SHUT_RDWR);
208 conn_put(con);
215} 209}
216 210
217static struct tipc_conn *tipc_alloc_conn(struct tipc_server *s) 211static struct tipc_conn *tipc_alloc_conn(struct tipc_server *s)
@@ -248,9 +242,10 @@ static struct tipc_conn *tipc_alloc_conn(struct tipc_server *s)
248 242
249static int tipc_receive_from_sock(struct tipc_conn *con) 243static int tipc_receive_from_sock(struct tipc_conn *con)
250{ 244{
251 struct msghdr msg = {};
252 struct tipc_server *s = con->server; 245 struct tipc_server *s = con->server;
246 struct sock *sk = con->sock->sk;
253 struct sockaddr_tipc addr; 247 struct sockaddr_tipc addr;
248 struct msghdr msg = {};
254 struct kvec iov; 249 struct kvec iov;
255 void *buf; 250 void *buf;
256 int ret; 251 int ret;
@@ -271,12 +266,15 @@ static int tipc_receive_from_sock(struct tipc_conn *con)
271 goto out_close; 266 goto out_close;
272 } 267 }
273 268
274 s->tipc_conn_recvmsg(sock_net(con->sock->sk), con->conid, &addr, 269 read_lock_bh(&sk->sk_callback_lock);
275 con->usr_data, buf, ret); 270 if (test_bit(CF_CONNECTED, &con->flags))
276 271 ret = s->tipc_conn_recvmsg(sock_net(con->sock->sk), con->conid,
272 &addr, con->usr_data, buf, ret);
273 read_unlock_bh(&sk->sk_callback_lock);
277 kmem_cache_free(s->rcvbuf_cache, buf); 274 kmem_cache_free(s->rcvbuf_cache, buf);
278 275 if (ret < 0)
279 return 0; 276 tipc_conn_terminate(s, con->conid);
277 return ret;
280 278
281out_close: 279out_close:
282 if (ret != -EWOULDBLOCK) 280 if (ret != -EWOULDBLOCK)
@@ -525,11 +523,17 @@ bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, u32 lower,
525void tipc_topsrv_kern_unsubscr(struct net *net, int conid) 523void tipc_topsrv_kern_unsubscr(struct net *net, int conid)
526{ 524{
527 struct tipc_conn *con; 525 struct tipc_conn *con;
526 struct tipc_server *srv;
528 527
529 con = tipc_conn_lookup(tipc_topsrv(net), conid); 528 con = tipc_conn_lookup(tipc_topsrv(net), conid);
530 if (!con) 529 if (!con)
531 return; 530 return;
532 tipc_close_conn(con); 531
532 test_and_clear_bit(CF_CONNECTED, &con->flags);
533 srv = con->server;
534 if (con->conid)
535 srv->tipc_conn_release(con->conid, con->usr_data);
536 conn_put(con);
533 conn_put(con); 537 conn_put(con);
534} 538}
535 539
diff --git a/net/tipc/server.h b/net/tipc/server.h
index 17f49ee44cfd..64df7513cd70 100644
--- a/net/tipc/server.h
+++ b/net/tipc/server.h
@@ -74,9 +74,9 @@ struct tipc_server {
74 int max_rcvbuf_size; 74 int max_rcvbuf_size;
75 void *(*tipc_conn_new)(int conid); 75 void *(*tipc_conn_new)(int conid);
76 void (*tipc_conn_release)(int conid, void *usr_data); 76 void (*tipc_conn_release)(int conid, void *usr_data);
77 void (*tipc_conn_recvmsg)(struct net *net, int conid, 77 int (*tipc_conn_recvmsg)(struct net *net, int conid,
78 struct sockaddr_tipc *addr, void *usr_data, 78 struct sockaddr_tipc *addr, void *usr_data,
79 void *buf, size_t len); 79 void *buf, size_t len);
80 struct sockaddr_tipc *saddr; 80 struct sockaddr_tipc *saddr;
81 char name[TIPC_SERVER_NAME_LEN]; 81 char name[TIPC_SERVER_NAME_LEN];
82 int imp; 82 int imp;
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 1f236271766c..d799e50ff722 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -772,7 +772,6 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq,
772 struct net *net = sock_net(sk); 772 struct net *net = sock_net(sk);
773 int mtu = tipc_bcast_get_mtu(net); 773 int mtu = tipc_bcast_get_mtu(net);
774 struct tipc_mc_method *method = &tsk->mc_method; 774 struct tipc_mc_method *method = &tsk->mc_method;
775 u32 domain = addr_domain(net, TIPC_CLUSTER_SCOPE);
776 struct sk_buff_head pkts; 775 struct sk_buff_head pkts;
777 struct tipc_nlist dsts; 776 struct tipc_nlist dsts;
778 int rc; 777 int rc;
@@ -788,7 +787,7 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq,
788 /* Lookup destination nodes */ 787 /* Lookup destination nodes */
789 tipc_nlist_init(&dsts, tipc_own_addr(net)); 788 tipc_nlist_init(&dsts, tipc_own_addr(net));
790 tipc_nametbl_lookup_dst_nodes(net, seq->type, seq->lower, 789 tipc_nametbl_lookup_dst_nodes(net, seq->type, seq->lower,
791 seq->upper, domain, &dsts); 790 seq->upper, &dsts);
792 if (!dsts.local && !dsts.remote) 791 if (!dsts.local && !dsts.remote)
793 return -EHOSTUNREACH; 792 return -EHOSTUNREACH;
794 793
@@ -2774,6 +2773,7 @@ static int tipc_sk_join(struct tipc_sock *tsk, struct tipc_group_req *mreq)
2774 if (rc) { 2773 if (rc) {
2775 tipc_group_delete(net, grp); 2774 tipc_group_delete(net, grp);
2776 tsk->group = NULL; 2775 tsk->group = NULL;
2776 return rc;
2777 } 2777 }
2778 /* Eliminate any risk that a broadcast overtakes sent JOINs */ 2778 /* Eliminate any risk that a broadcast overtakes sent JOINs */
2779 tsk->mc_method.rcast = true; 2779 tsk->mc_method.rcast = true;
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index 44df528ed6ab..68e26470c516 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -289,17 +289,16 @@ static struct tipc_subscription *tipc_subscrp_create(struct net *net,
289 return sub; 289 return sub;
290} 290}
291 291
292static void tipc_subscrp_subscribe(struct net *net, struct tipc_subscr *s, 292static int tipc_subscrp_subscribe(struct net *net, struct tipc_subscr *s,
293 struct tipc_subscriber *subscriber, int swap, 293 struct tipc_subscriber *subscriber, int swap,
294 bool status) 294 bool status)
295{ 295{
296 struct tipc_net *tn = net_generic(net, tipc_net_id);
297 struct tipc_subscription *sub = NULL; 296 struct tipc_subscription *sub = NULL;
298 u32 timeout; 297 u32 timeout;
299 298
300 sub = tipc_subscrp_create(net, s, swap); 299 sub = tipc_subscrp_create(net, s, swap);
301 if (!sub) 300 if (!sub)
302 return tipc_conn_terminate(tn->topsrv, subscriber->conid); 301 return -1;
303 302
304 spin_lock_bh(&subscriber->lock); 303 spin_lock_bh(&subscriber->lock);
305 list_add(&sub->subscrp_list, &subscriber->subscrp_list); 304 list_add(&sub->subscrp_list, &subscriber->subscrp_list);
@@ -313,6 +312,7 @@ static void tipc_subscrp_subscribe(struct net *net, struct tipc_subscr *s,
313 312
314 if (timeout != TIPC_WAIT_FOREVER) 313 if (timeout != TIPC_WAIT_FOREVER)
315 mod_timer(&sub->timer, jiffies + msecs_to_jiffies(timeout)); 314 mod_timer(&sub->timer, jiffies + msecs_to_jiffies(timeout));
315 return 0;
316} 316}
317 317
318/* Handle one termination request for the subscriber */ 318/* Handle one termination request for the subscriber */
@@ -322,9 +322,9 @@ static void tipc_subscrb_release_cb(int conid, void *usr_data)
322} 322}
323 323
324/* Handle one request to create a new subscription for the subscriber */ 324/* Handle one request to create a new subscription for the subscriber */
325static void tipc_subscrb_rcv_cb(struct net *net, int conid, 325static int tipc_subscrb_rcv_cb(struct net *net, int conid,
326 struct sockaddr_tipc *addr, void *usr_data, 326 struct sockaddr_tipc *addr, void *usr_data,
327 void *buf, size_t len) 327 void *buf, size_t len)
328{ 328{
329 struct tipc_subscriber *subscriber = usr_data; 329 struct tipc_subscriber *subscriber = usr_data;
330 struct tipc_subscr *s = (struct tipc_subscr *)buf; 330 struct tipc_subscr *s = (struct tipc_subscr *)buf;
@@ -338,10 +338,11 @@ static void tipc_subscrb_rcv_cb(struct net *net, int conid,
338 /* Detect & process a subscription cancellation request */ 338 /* Detect & process a subscription cancellation request */
339 if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) { 339 if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) {
340 s->filter &= ~htohl(TIPC_SUB_CANCEL, swap); 340 s->filter &= ~htohl(TIPC_SUB_CANCEL, swap);
341 return tipc_subscrp_cancel(s, subscriber); 341 tipc_subscrp_cancel(s, subscriber);
342 return 0;
342 } 343 }
343 status = !(s->filter & htohl(TIPC_SUB_NO_STATUS, swap)); 344 status = !(s->filter & htohl(TIPC_SUB_NO_STATUS, swap));
344 tipc_subscrp_subscribe(net, s, subscriber, swap, status); 345 return tipc_subscrp_subscribe(net, s, subscriber, swap, status);
345} 346}
346 347
347/* Handle one request to establish a new subscriber */ 348/* Handle one request to establish a new subscriber */