xref: /openbmc/linux/net/tipc/bcast.c (revision 9999974a)
1b97bf3fdSPer Liden /*
2b97bf3fdSPer Liden  * net/tipc/bcast.c: TIPC broadcast code
3b97bf3fdSPer Liden  *
49999974aSJon Paul Maloy  * Copyright (c) 2004-2006, 2014-2016, Ericsson AB
5b97bf3fdSPer Liden  * Copyright (c) 2004, Intel Corporation.
62d627b92SAllan Stephens  * Copyright (c) 2005, 2010-2011, Wind River Systems
7b97bf3fdSPer Liden  * All rights reserved.
8b97bf3fdSPer Liden  *
9b97bf3fdSPer Liden  * Redistribution and use in source and binary forms, with or without
10b97bf3fdSPer Liden  * modification, are permitted provided that the following conditions are met:
11b97bf3fdSPer Liden  *
129ea1fd3cSPer Liden  * 1. Redistributions of source code must retain the above copyright
139ea1fd3cSPer Liden  *    notice, this list of conditions and the following disclaimer.
149ea1fd3cSPer Liden  * 2. Redistributions in binary form must reproduce the above copyright
159ea1fd3cSPer Liden  *    notice, this list of conditions and the following disclaimer in the
169ea1fd3cSPer Liden  *    documentation and/or other materials provided with the distribution.
179ea1fd3cSPer Liden  * 3. Neither the names of the copyright holders nor the names of its
189ea1fd3cSPer Liden  *    contributors may be used to endorse or promote products derived from
199ea1fd3cSPer Liden  *    this software without specific prior written permission.
209ea1fd3cSPer Liden  *
219ea1fd3cSPer Liden  * Alternatively, this software may be distributed under the terms of the
229ea1fd3cSPer Liden  * GNU General Public License ("GPL") version 2 as published by the Free
239ea1fd3cSPer Liden  * Software Foundation.
24b97bf3fdSPer Liden  *
25b97bf3fdSPer Liden  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26b97bf3fdSPer Liden  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27b97bf3fdSPer Liden  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28b97bf3fdSPer Liden  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29b97bf3fdSPer Liden  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30b97bf3fdSPer Liden  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31b97bf3fdSPer Liden  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32b97bf3fdSPer Liden  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33b97bf3fdSPer Liden  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34b97bf3fdSPer Liden  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35b97bf3fdSPer Liden  * POSSIBILITY OF SUCH DAMAGE.
36b97bf3fdSPer Liden  */
37b97bf3fdSPer Liden 
386beb19a6SJon Paul Maloy #include <linux/tipc_config.h>
39078bec82SJon Paul Maloy #include "socket.h"
40078bec82SJon Paul Maloy #include "msg.h"
41b97bf3fdSPer Liden #include "bcast.h"
429f6bdcd4SAllan Stephens #include "name_distr.h"
436beb19a6SJon Paul Maloy #include "link.h"
446beb19a6SJon Paul Maloy #include "node.h"
45b97bf3fdSPer Liden 
4653387c4eSJon Paul Maloy #define	BCLINK_WIN_DEFAULT	50	/* bcast link window size (default) */
4753387c4eSJon Paul Maloy #define	BCLINK_WIN_MIN	        32	/* bcast minimum link window size */
48c47e9b91SAllan Stephens 
493aec9cc9SAllan Stephens const char tipc_bclink_name[] = "broadcast-link";
50b97bf3fdSPer Liden 
516beb19a6SJon Paul Maloy /**
522af5ae37SJon Paul Maloy  * struct tipc_bc_base - base structure for keeping broadcast send state
53b06b281eSJon Paul Maloy  * @link: broadcast send link structure
542af5ae37SJon Paul Maloy  * @inputq: data input queue; will only carry SOCK_WAKEUP messages
552af5ae37SJon Paul Maloy  * @dest: array keeping number of reachable destinations per bearer
562af5ae37SJon Paul Maloy  * @primary_bearer: a bearer having links to all broadcast destinations, if any
579999974aSJon Paul Maloy  * @bcast_support: indicates if primary bearer, if any, supports broadcast
586beb19a6SJon Paul Maloy  */
596beb19a6SJon Paul Maloy struct tipc_bc_base {
6032301906SJon Paul Maloy 	struct tipc_link *link;
616beb19a6SJon Paul Maloy 	struct sk_buff_head inputq;
62b06b281eSJon Paul Maloy 	int dests[MAX_BEARERS];
63b06b281eSJon Paul Maloy 	int primary_bearer;
649999974aSJon Paul Maloy 	bool bcast_support;
656beb19a6SJon Paul Maloy };
666beb19a6SJon Paul Maloy 
675fd9fd63SJon Paul Maloy static struct tipc_bc_base *tipc_bc_base(struct net *net)
685fd9fd63SJon Paul Maloy {
695fd9fd63SJon Paul Maloy 	return tipc_net(net)->bcbase;
705fd9fd63SJon Paul Maloy }
715fd9fd63SJon Paul Maloy 
72959e1781SJon Paul Maloy int tipc_bcast_get_mtu(struct net *net)
73078bec82SJon Paul Maloy {
74959e1781SJon Paul Maloy 	return tipc_link_mtu(tipc_bc_sndlink(net));
75078bec82SJon Paul Maloy }
76078bec82SJon Paul Maloy 
77b06b281eSJon Paul Maloy /* tipc_bcbase_select_primary(): find a bearer with links to all destinations,
78b06b281eSJon Paul Maloy  *                               if any, and make it primary bearer
79b06b281eSJon Paul Maloy  */
80b06b281eSJon Paul Maloy static void tipc_bcbase_select_primary(struct net *net)
81b06b281eSJon Paul Maloy {
82b06b281eSJon Paul Maloy 	struct tipc_bc_base *bb = tipc_bc_base(net);
83b06b281eSJon Paul Maloy 	int all_dests =  tipc_link_bc_peers(bb->link);
849999974aSJon Paul Maloy 	int i, mtu, prim;
85b06b281eSJon Paul Maloy 
86b06b281eSJon Paul Maloy 	bb->primary_bearer = INVALID_BEARER_ID;
879999974aSJon Paul Maloy 	bb->bcast_support = true;
88b06b281eSJon Paul Maloy 
89b06b281eSJon Paul Maloy 	if (!all_dests)
90b06b281eSJon Paul Maloy 		return;
91b06b281eSJon Paul Maloy 
92b06b281eSJon Paul Maloy 	for (i = 0; i < MAX_BEARERS; i++) {
93959e1781SJon Paul Maloy 		if (!bb->dests[i])
94959e1781SJon Paul Maloy 			continue;
95959e1781SJon Paul Maloy 
96959e1781SJon Paul Maloy 		mtu = tipc_bearer_mtu(net, i);
97959e1781SJon Paul Maloy 		if (mtu < tipc_link_mtu(bb->link))
98959e1781SJon Paul Maloy 			tipc_link_set_mtu(bb->link, mtu);
999999974aSJon Paul Maloy 		bb->bcast_support &= tipc_bearer_bcast_support(net, i);
100b06b281eSJon Paul Maloy 		if (bb->dests[i] < all_dests)
101b06b281eSJon Paul Maloy 			continue;
102b06b281eSJon Paul Maloy 
103b06b281eSJon Paul Maloy 		bb->primary_bearer = i;
104b06b281eSJon Paul Maloy 
105b06b281eSJon Paul Maloy 		/* Reduce risk that all nodes select same primary */
106b06b281eSJon Paul Maloy 		if ((i ^ tipc_own_addr(net)) & 1)
107b06b281eSJon Paul Maloy 			break;
108b06b281eSJon Paul Maloy 	}
1099999974aSJon Paul Maloy 	prim = bb->primary_bearer;
1109999974aSJon Paul Maloy 	if (prim != INVALID_BEARER_ID)
1119999974aSJon Paul Maloy 		bb->bcast_support = tipc_bearer_bcast_support(net, prim);
112b06b281eSJon Paul Maloy }
113b06b281eSJon Paul Maloy 
114b06b281eSJon Paul Maloy void tipc_bcast_inc_bearer_dst_cnt(struct net *net, int bearer_id)
115b06b281eSJon Paul Maloy {
116b06b281eSJon Paul Maloy 	struct tipc_bc_base *bb = tipc_bc_base(net);
117b06b281eSJon Paul Maloy 
118b06b281eSJon Paul Maloy 	tipc_bcast_lock(net);
119b06b281eSJon Paul Maloy 	bb->dests[bearer_id]++;
120b06b281eSJon Paul Maloy 	tipc_bcbase_select_primary(net);
121b06b281eSJon Paul Maloy 	tipc_bcast_unlock(net);
122b06b281eSJon Paul Maloy }
123b06b281eSJon Paul Maloy 
124b06b281eSJon Paul Maloy void tipc_bcast_dec_bearer_dst_cnt(struct net *net, int bearer_id)
125b06b281eSJon Paul Maloy {
126b06b281eSJon Paul Maloy 	struct tipc_bc_base *bb = tipc_bc_base(net);
127b06b281eSJon Paul Maloy 
128b06b281eSJon Paul Maloy 	tipc_bcast_lock(net);
129b06b281eSJon Paul Maloy 	bb->dests[bearer_id]--;
130b06b281eSJon Paul Maloy 	tipc_bcbase_select_primary(net);
131b06b281eSJon Paul Maloy 	tipc_bcast_unlock(net);
132b06b281eSJon Paul Maloy }
133b06b281eSJon Paul Maloy 
134b06b281eSJon Paul Maloy /* tipc_bcbase_xmit - broadcast a packet queue across one or more bearers
135b06b281eSJon Paul Maloy  *
136b06b281eSJon Paul Maloy  * Note that number of reachable destinations, as indicated in the dests[]
137b06b281eSJon Paul Maloy  * array, may transitionally differ from the number of destinations indicated
138b06b281eSJon Paul Maloy  * in each sent buffer. We can sustain this. Excess destination nodes will
139b06b281eSJon Paul Maloy  * drop and never acknowledge the unexpected packets, and missing destinations
140b06b281eSJon Paul Maloy  * will either require retransmission (if they are just about to be added to
141b06b281eSJon Paul Maloy  * the bearer), or be removed from the buffer's 'ackers' counter (if they
142b06b281eSJon Paul Maloy  * just went down)
143b06b281eSJon Paul Maloy  */
144b06b281eSJon Paul Maloy static void tipc_bcbase_xmit(struct net *net, struct sk_buff_head *xmitq)
145b06b281eSJon Paul Maloy {
146b06b281eSJon Paul Maloy 	int bearer_id;
147b06b281eSJon Paul Maloy 	struct tipc_bc_base *bb = tipc_bc_base(net);
148b06b281eSJon Paul Maloy 	struct sk_buff *skb, *_skb;
149b06b281eSJon Paul Maloy 	struct sk_buff_head _xmitq;
150b06b281eSJon Paul Maloy 
151b06b281eSJon Paul Maloy 	if (skb_queue_empty(xmitq))
152b06b281eSJon Paul Maloy 		return;
153b06b281eSJon Paul Maloy 
154b06b281eSJon Paul Maloy 	/* The typical case: at least one bearer has links to all nodes */
155b06b281eSJon Paul Maloy 	bearer_id = bb->primary_bearer;
156b06b281eSJon Paul Maloy 	if (bearer_id >= 0) {
157b06b281eSJon Paul Maloy 		tipc_bearer_bc_xmit(net, bearer_id, xmitq);
158b06b281eSJon Paul Maloy 		return;
159b06b281eSJon Paul Maloy 	}
160b06b281eSJon Paul Maloy 
161b06b281eSJon Paul Maloy 	/* We have to transmit across all bearers */
162b06b281eSJon Paul Maloy 	skb_queue_head_init(&_xmitq);
163b06b281eSJon Paul Maloy 	for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) {
164b06b281eSJon Paul Maloy 		if (!bb->dests[bearer_id])
165b06b281eSJon Paul Maloy 			continue;
166b06b281eSJon Paul Maloy 
167b06b281eSJon Paul Maloy 		skb_queue_walk(xmitq, skb) {
168b06b281eSJon Paul Maloy 			_skb = pskb_copy_for_clone(skb, GFP_ATOMIC);
169b06b281eSJon Paul Maloy 			if (!_skb)
170b06b281eSJon Paul Maloy 				break;
171b06b281eSJon Paul Maloy 			__skb_queue_tail(&_xmitq, _skb);
172b06b281eSJon Paul Maloy 		}
173b06b281eSJon Paul Maloy 		tipc_bearer_bc_xmit(net, bearer_id, &_xmitq);
174b06b281eSJon Paul Maloy 	}
175b06b281eSJon Paul Maloy 	__skb_queue_purge(xmitq);
176b06b281eSJon Paul Maloy 	__skb_queue_purge(&_xmitq);
177b06b281eSJon Paul Maloy }
178b06b281eSJon Paul Maloy 
1796beb19a6SJon Paul Maloy /* tipc_bcast_xmit - deliver buffer chain to all nodes in cluster
180078bec82SJon Paul Maloy  *                    and to identified node local sockets
181f2f9800dSYing Xue  * @net: the applicable net namespace
182a6ca1094SYing Xue  * @list: chain of buffers containing message
183365ad353SJon Paul Maloy  * Consumes the buffer chain.
184078bec82SJon Paul Maloy  * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE
185078bec82SJon Paul Maloy  */
1866beb19a6SJon Paul Maloy int tipc_bcast_xmit(struct net *net, struct sk_buff_head *list)
187078bec82SJon Paul Maloy {
1882f566124SJon Paul Maloy 	struct tipc_link *l = tipc_bc_sndlink(net);
1892f566124SJon Paul Maloy 	struct sk_buff_head xmitq, inputq, rcvq;
190078bec82SJon Paul Maloy 	int rc = 0;
191078bec82SJon Paul Maloy 
1922f566124SJon Paul Maloy 	__skb_queue_head_init(&rcvq);
1932f566124SJon Paul Maloy 	__skb_queue_head_init(&xmitq);
1942f566124SJon Paul Maloy 	skb_queue_head_init(&inputq);
1952f566124SJon Paul Maloy 
1962f566124SJon Paul Maloy 	/* Prepare message clone for local node */
1972f566124SJon Paul Maloy 	if (unlikely(!tipc_msg_reassemble(list, &rcvq)))
198078bec82SJon Paul Maloy 		return -EHOSTUNREACH;
19922d85c79SJon Paul Maloy 
2002f566124SJon Paul Maloy 	tipc_bcast_lock(net);
2012f566124SJon Paul Maloy 	if (tipc_link_bc_peers(l))
2022f566124SJon Paul Maloy 		rc = tipc_link_xmit(l, list, &xmitq);
2032f566124SJon Paul Maloy 	tipc_bcast_unlock(net);
204078bec82SJon Paul Maloy 
2052f566124SJon Paul Maloy 	/* Don't send to local node if adding to link failed */
206365ad353SJon Paul Maloy 	if (unlikely(rc && (rc != -ELINKCONG))) {
2072f566124SJon Paul Maloy 		__skb_queue_purge(&rcvq);
208cb1b7280SJon Paul Maloy 		return rc;
209cb1b7280SJon Paul Maloy 	}
21052666986SJon Paul Maloy 
2112f566124SJon Paul Maloy 	/* Broadcast to all nodes, inluding local node */
212b06b281eSJon Paul Maloy 	tipc_bcbase_xmit(net, &xmitq);
2132f566124SJon Paul Maloy 	tipc_sk_mcast_rcv(net, &rcvq, &inputq);
2142f566124SJon Paul Maloy 	__skb_queue_purge(list);
215365ad353SJon Paul Maloy 	return rc;
216078bec82SJon Paul Maloy }
21752666986SJon Paul Maloy 
21852666986SJon Paul Maloy /* tipc_bcast_rcv - receive a broadcast packet, and deliver to rcv link
21952666986SJon Paul Maloy  *
22052666986SJon Paul Maloy  * RCU is locked, no other locks set
22152666986SJon Paul Maloy  */
22252666986SJon Paul Maloy int tipc_bcast_rcv(struct net *net, struct tipc_link *l, struct sk_buff *skb)
22352666986SJon Paul Maloy {
22452666986SJon Paul Maloy 	struct tipc_msg *hdr = buf_msg(skb);
22552666986SJon Paul Maloy 	struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq;
22652666986SJon Paul Maloy 	struct sk_buff_head xmitq;
22752666986SJon Paul Maloy 	int rc;
22852666986SJon Paul Maloy 
22952666986SJon Paul Maloy 	__skb_queue_head_init(&xmitq);
23052666986SJon Paul Maloy 
23152666986SJon Paul Maloy 	if (msg_mc_netid(hdr) != tipc_netid(net) || !tipc_link_is_up(l)) {
23252666986SJon Paul Maloy 		kfree_skb(skb);
23352666986SJon Paul Maloy 		return 0;
23452666986SJon Paul Maloy 	}
23552666986SJon Paul Maloy 
23652666986SJon Paul Maloy 	tipc_bcast_lock(net);
23752666986SJon Paul Maloy 	if (msg_user(hdr) == BCAST_PROTOCOL)
23852666986SJon Paul Maloy 		rc = tipc_link_bc_nack_rcv(l, skb, &xmitq);
23952666986SJon Paul Maloy 	else
24052666986SJon Paul Maloy 		rc = tipc_link_rcv(l, skb, NULL);
24152666986SJon Paul Maloy 	tipc_bcast_unlock(net);
24252666986SJon Paul Maloy 
243b06b281eSJon Paul Maloy 	tipc_bcbase_xmit(net, &xmitq);
24452666986SJon Paul Maloy 
24552666986SJon Paul Maloy 	/* Any socket wakeup messages ? */
24652666986SJon Paul Maloy 	if (!skb_queue_empty(inputq))
24752666986SJon Paul Maloy 		tipc_sk_rcv(net, inputq);
24852666986SJon Paul Maloy 
24952666986SJon Paul Maloy 	return rc;
25052666986SJon Paul Maloy }
25152666986SJon Paul Maloy 
25252666986SJon Paul Maloy /* tipc_bcast_ack_rcv - receive and handle a broadcast acknowledge
25352666986SJon Paul Maloy  *
25452666986SJon Paul Maloy  * RCU is locked, no other locks set
25552666986SJon Paul Maloy  */
25606bd2b1eSJon Paul Maloy void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l,
25706bd2b1eSJon Paul Maloy 			struct tipc_msg *hdr)
25852666986SJon Paul Maloy {
25952666986SJon Paul Maloy 	struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq;
26006bd2b1eSJon Paul Maloy 	u16 acked = msg_bcast_ack(hdr);
26152666986SJon Paul Maloy 	struct sk_buff_head xmitq;
26252666986SJon Paul Maloy 
26306bd2b1eSJon Paul Maloy 	/* Ignore bc acks sent by peer before bcast synch point was received */
26406bd2b1eSJon Paul Maloy 	if (msg_bc_ack_invalid(hdr))
26506bd2b1eSJon Paul Maloy 		return;
26606bd2b1eSJon Paul Maloy 
26752666986SJon Paul Maloy 	__skb_queue_head_init(&xmitq);
26852666986SJon Paul Maloy 
26952666986SJon Paul Maloy 	tipc_bcast_lock(net);
27052666986SJon Paul Maloy 	tipc_link_bc_ack_rcv(l, acked, &xmitq);
27152666986SJon Paul Maloy 	tipc_bcast_unlock(net);
27252666986SJon Paul Maloy 
273b06b281eSJon Paul Maloy 	tipc_bcbase_xmit(net, &xmitq);
27452666986SJon Paul Maloy 
27552666986SJon Paul Maloy 	/* Any socket wakeup messages ? */
27652666986SJon Paul Maloy 	if (!skb_queue_empty(inputq))
27752666986SJon Paul Maloy 		tipc_sk_rcv(net, inputq);
27852666986SJon Paul Maloy }
27952666986SJon Paul Maloy 
28052666986SJon Paul Maloy /* tipc_bcast_synch_rcv -  check and update rcv link with peer's send state
28152666986SJon Paul Maloy  *
28252666986SJon Paul Maloy  * RCU is locked, no other locks set
28352666986SJon Paul Maloy  */
28402d11ca2SJon Paul Maloy int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,
28552666986SJon Paul Maloy 			struct tipc_msg *hdr)
28652666986SJon Paul Maloy {
28752666986SJon Paul Maloy 	struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq;
28852666986SJon Paul Maloy 	struct sk_buff_head xmitq;
28902d11ca2SJon Paul Maloy 	int rc = 0;
29052666986SJon Paul Maloy 
29152666986SJon Paul Maloy 	__skb_queue_head_init(&xmitq);
29252666986SJon Paul Maloy 
29352666986SJon Paul Maloy 	tipc_bcast_lock(net);
29406bd2b1eSJon Paul Maloy 	if (msg_type(hdr) != STATE_MSG) {
29506bd2b1eSJon Paul Maloy 		tipc_link_bc_init_rcv(l, hdr);
29606bd2b1eSJon Paul Maloy 	} else if (!msg_bc_ack_invalid(hdr)) {
29752666986SJon Paul Maloy 		tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr), &xmitq);
29802d11ca2SJon Paul Maloy 		rc = tipc_link_bc_sync_rcv(l, hdr, &xmitq);
29952666986SJon Paul Maloy 	}
30052666986SJon Paul Maloy 	tipc_bcast_unlock(net);
30152666986SJon Paul Maloy 
302b06b281eSJon Paul Maloy 	tipc_bcbase_xmit(net, &xmitq);
30352666986SJon Paul Maloy 
30452666986SJon Paul Maloy 	/* Any socket wakeup messages ? */
30552666986SJon Paul Maloy 	if (!skb_queue_empty(inputq))
30652666986SJon Paul Maloy 		tipc_sk_rcv(net, inputq);
30702d11ca2SJon Paul Maloy 	return rc;
30852666986SJon Paul Maloy }
30952666986SJon Paul Maloy 
31052666986SJon Paul Maloy /* tipc_bcast_add_peer - add a peer node to broadcast link and bearer
31152666986SJon Paul Maloy  *
31252666986SJon Paul Maloy  * RCU is locked, node lock is set
31352666986SJon Paul Maloy  */
314b06b281eSJon Paul Maloy void tipc_bcast_add_peer(struct net *net, struct tipc_link *uc_l,
31552666986SJon Paul Maloy 			 struct sk_buff_head *xmitq)
31652666986SJon Paul Maloy {
31752666986SJon Paul Maloy 	struct tipc_link *snd_l = tipc_bc_sndlink(net);
31852666986SJon Paul Maloy 
319b06b281eSJon Paul Maloy 	tipc_bcast_lock(net);
32052666986SJon Paul Maloy 	tipc_link_add_bc_peer(snd_l, uc_l, xmitq);
321b06b281eSJon Paul Maloy 	tipc_bcbase_select_primary(net);
322b06b281eSJon Paul Maloy 	tipc_bcast_unlock(net);
32352666986SJon Paul Maloy }
32452666986SJon Paul Maloy 
32552666986SJon Paul Maloy /* tipc_bcast_remove_peer - remove a peer node from broadcast link and bearer
32652666986SJon Paul Maloy  *
32752666986SJon Paul Maloy  * RCU is locked, node lock is set
32852666986SJon Paul Maloy  */
329b06b281eSJon Paul Maloy void tipc_bcast_remove_peer(struct net *net, struct tipc_link *rcv_l)
33052666986SJon Paul Maloy {
33152666986SJon Paul Maloy 	struct tipc_link *snd_l = tipc_bc_sndlink(net);
332b06b281eSJon Paul Maloy 	struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq;
33352666986SJon Paul Maloy 	struct sk_buff_head xmitq;
33452666986SJon Paul Maloy 
33552666986SJon Paul Maloy 	__skb_queue_head_init(&xmitq);
33652666986SJon Paul Maloy 
337b06b281eSJon Paul Maloy 	tipc_bcast_lock(net);
33852666986SJon Paul Maloy 	tipc_link_remove_bc_peer(snd_l, rcv_l, &xmitq);
339b06b281eSJon Paul Maloy 	tipc_bcbase_select_primary(net);
340b06b281eSJon Paul Maloy 	tipc_bcast_unlock(net);
34152666986SJon Paul Maloy 
342b06b281eSJon Paul Maloy 	tipc_bcbase_xmit(net, &xmitq);
34352666986SJon Paul Maloy 
34452666986SJon Paul Maloy 	/* Any socket wakeup messages ? */
34552666986SJon Paul Maloy 	if (!skb_queue_empty(inputq))
34652666986SJon Paul Maloy 		tipc_sk_rcv(net, inputq);
34752666986SJon Paul Maloy }
34852666986SJon Paul Maloy 
3491da46568SYing Xue int tipc_bclink_reset_stats(struct net *net)
350b97bf3fdSPer Liden {
35138206d59SJon Paul Maloy 	struct tipc_link *l = tipc_bc_sndlink(net);
3521da46568SYing Xue 
35338206d59SJon Paul Maloy 	if (!l)
354b97bf3fdSPer Liden 		return -ENOPROTOOPT;
355b97bf3fdSPer Liden 
3562af5ae37SJon Paul Maloy 	tipc_bcast_lock(net);
35738206d59SJon Paul Maloy 	tipc_link_reset_stats(l);
3582af5ae37SJon Paul Maloy 	tipc_bcast_unlock(net);
3590e35fd5eSAllan Stephens 	return 0;
360b97bf3fdSPer Liden }
361b97bf3fdSPer Liden 
3622af5ae37SJon Paul Maloy static int tipc_bc_link_set_queue_limits(struct net *net, u32 limit)
363b97bf3fdSPer Liden {
3642af5ae37SJon Paul Maloy 	struct tipc_link *l = tipc_bc_sndlink(net);
3651da46568SYing Xue 
3662af5ae37SJon Paul Maloy 	if (!l)
367b97bf3fdSPer Liden 		return -ENOPROTOOPT;
36853387c4eSJon Paul Maloy 	if (limit < BCLINK_WIN_MIN)
36953387c4eSJon Paul Maloy 		limit = BCLINK_WIN_MIN;
37053387c4eSJon Paul Maloy 	if (limit > TIPC_MAX_LINK_WIN)
371b97bf3fdSPer Liden 		return -EINVAL;
3722af5ae37SJon Paul Maloy 	tipc_bcast_lock(net);
3732af5ae37SJon Paul Maloy 	tipc_link_set_queue_limits(l, limit);
3742af5ae37SJon Paul Maloy 	tipc_bcast_unlock(net);
3750e35fd5eSAllan Stephens 	return 0;
376b97bf3fdSPer Liden }
377b97bf3fdSPer Liden 
378670f4f88SRichard Alpe int tipc_nl_bc_link_set(struct net *net, struct nlattr *attrs[])
379670f4f88SRichard Alpe {
380670f4f88SRichard Alpe 	int err;
381670f4f88SRichard Alpe 	u32 win;
382670f4f88SRichard Alpe 	struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
383670f4f88SRichard Alpe 
384670f4f88SRichard Alpe 	if (!attrs[TIPC_NLA_LINK_PROP])
385670f4f88SRichard Alpe 		return -EINVAL;
386670f4f88SRichard Alpe 
387670f4f88SRichard Alpe 	err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_LINK_PROP], props);
388670f4f88SRichard Alpe 	if (err)
389670f4f88SRichard Alpe 		return err;
390670f4f88SRichard Alpe 
391670f4f88SRichard Alpe 	if (!props[TIPC_NLA_PROP_WIN])
392670f4f88SRichard Alpe 		return -EOPNOTSUPP;
393670f4f88SRichard Alpe 
394670f4f88SRichard Alpe 	win = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
395670f4f88SRichard Alpe 
3962af5ae37SJon Paul Maloy 	return tipc_bc_link_set_queue_limits(net, win);
397670f4f88SRichard Alpe }
398670f4f88SRichard Alpe 
3996beb19a6SJon Paul Maloy int tipc_bcast_init(struct net *net)
400b97bf3fdSPer Liden {
40132301906SJon Paul Maloy 	struct tipc_net *tn = tipc_net(net);
40232301906SJon Paul Maloy 	struct tipc_bc_base *bb = NULL;
40332301906SJon Paul Maloy 	struct tipc_link *l = NULL;
4047f9f95d9SYing Xue 
40532301906SJon Paul Maloy 	bb = kzalloc(sizeof(*bb), GFP_ATOMIC);
40632301906SJon Paul Maloy 	if (!bb)
40732301906SJon Paul Maloy 		goto enomem;
40832301906SJon Paul Maloy 	tn->bcbase = bb;
4090043550bSJon Paul Maloy 	spin_lock_init(&tipc_net(net)->bclock);
4105fd9fd63SJon Paul Maloy 
411c72fa872SJon Paul Maloy 	if (!tipc_link_bc_create(net, 0, 0,
412959e1781SJon Paul Maloy 				 U16_MAX,
41332301906SJon Paul Maloy 				 BCLINK_WIN_DEFAULT,
414fd556f20SJon Paul Maloy 				 0,
41532301906SJon Paul Maloy 				 &bb->inputq,
4162af5ae37SJon Paul Maloy 				 NULL,
41752666986SJon Paul Maloy 				 NULL,
41832301906SJon Paul Maloy 				 &l))
41932301906SJon Paul Maloy 		goto enomem;
42032301906SJon Paul Maloy 	bb->link = l;
42132301906SJon Paul Maloy 	tn->bcl = l;
422eb8b00f5SYing Xue 	return 0;
42332301906SJon Paul Maloy enomem:
42432301906SJon Paul Maloy 	kfree(bb);
42532301906SJon Paul Maloy 	kfree(l);
42632301906SJon Paul Maloy 	return -ENOMEM;
427b97bf3fdSPer Liden }
428b97bf3fdSPer Liden 
4296beb19a6SJon Paul Maloy void tipc_bcast_stop(struct net *net)
430b97bf3fdSPer Liden {
4317f9f95d9SYing Xue 	struct tipc_net *tn = net_generic(net, tipc_net_id);
4327f9f95d9SYing Xue 
433eb8b00f5SYing Xue 	synchronize_net();
4346beb19a6SJon Paul Maloy 	kfree(tn->bcbase);
43532301906SJon Paul Maloy 	kfree(tn->bcl);
436b97bf3fdSPer Liden }
437