1b97bf3fdSPer Liden /* 2b97bf3fdSPer Liden * net/tipc/bcast.c: TIPC broadcast code 3b97bf3fdSPer Liden * 44c94cc2dSJon Maloy * Copyright (c) 2004-2006, 2014-2017, 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" 426beb19a6SJon Paul Maloy #include "link.h" 432ae0b8afSJon Paul Maloy #include "name_table.h" 44b97bf3fdSPer Liden 4553387c4eSJon Paul Maloy #define BCLINK_WIN_DEFAULT 50 /* bcast link window size (default) */ 4653387c4eSJon Paul Maloy #define BCLINK_WIN_MIN 32 /* bcast minimum link window size */ 47c47e9b91SAllan Stephens 483aec9cc9SAllan Stephens const char tipc_bclink_name[] = "broadcast-link"; 49b97bf3fdSPer Liden 506beb19a6SJon Paul Maloy /** 512af5ae37SJon Paul Maloy * struct tipc_bc_base - base structure for keeping broadcast send state 52b06b281eSJon Paul Maloy * @link: broadcast send link structure 532af5ae37SJon Paul Maloy * @inputq: data input queue; will only carry SOCK_WAKEUP messages 542af5ae37SJon Paul Maloy * @dest: array keeping number of reachable destinations per bearer 552af5ae37SJon Paul Maloy * @primary_bearer: a bearer having links to all broadcast destinations, if any 569999974aSJon Paul Maloy * @bcast_support: indicates if primary bearer, if any, supports broadcast 5701fd12bbSJon Paul Maloy * @rcast_support: indicates if all peer nodes support replicast 5801fd12bbSJon Paul Maloy * @rc_ratio: dest count as percentage of cluster size where send method changes 5901fd12bbSJon Paul Maloy * @bc_threshold: calculated drom rc_ratio; if dests > threshold use broadcast 606beb19a6SJon Paul Maloy */ 616beb19a6SJon Paul Maloy struct tipc_bc_base { 6232301906SJon Paul Maloy struct tipc_link *link; 636beb19a6SJon Paul Maloy struct sk_buff_head inputq; 64b06b281eSJon Paul Maloy int dests[MAX_BEARERS]; 65b06b281eSJon Paul Maloy int primary_bearer; 669999974aSJon Paul Maloy bool bcast_support; 6701fd12bbSJon Paul Maloy bool rcast_support; 6801fd12bbSJon Paul Maloy int rc_ratio; 6901fd12bbSJon Paul Maloy int bc_threshold; 706beb19a6SJon Paul Maloy }; 716beb19a6SJon Paul Maloy 725fd9fd63SJon Paul Maloy static struct tipc_bc_base *tipc_bc_base(struct net *net) 735fd9fd63SJon Paul Maloy { 745fd9fd63SJon Paul Maloy return tipc_net(net)->bcbase; 755fd9fd63SJon Paul Maloy } 765fd9fd63SJon Paul Maloy 774c94cc2dSJon Maloy /* tipc_bcast_get_mtu(): -get the MTU currently used by broadcast link 784c94cc2dSJon Maloy * Note: the MTU is decremented to give room for a tunnel header, in 794c94cc2dSJon Maloy * case the message needs to be sent as replicast 804c94cc2dSJon Maloy */ 81959e1781SJon Paul Maloy int tipc_bcast_get_mtu(struct net *net) 82078bec82SJon Paul Maloy { 83a853e4c6SJon Paul Maloy return tipc_link_mtu(tipc_bc_sndlink(net)) - INT_H_SIZE; 84078bec82SJon Paul Maloy } 85078bec82SJon Paul Maloy 8601fd12bbSJon Paul Maloy void tipc_bcast_disable_rcast(struct net *net) 8701fd12bbSJon Paul Maloy { 8801fd12bbSJon Paul Maloy tipc_bc_base(net)->rcast_support = false; 8901fd12bbSJon Paul Maloy } 9001fd12bbSJon Paul Maloy 9101fd12bbSJon Paul Maloy static void tipc_bcbase_calc_bc_threshold(struct net *net) 9201fd12bbSJon Paul Maloy { 9301fd12bbSJon Paul Maloy struct tipc_bc_base *bb = tipc_bc_base(net); 9401fd12bbSJon Paul Maloy int cluster_size = tipc_link_bc_peers(tipc_bc_sndlink(net)); 9501fd12bbSJon Paul Maloy 9601fd12bbSJon Paul Maloy bb->bc_threshold = 1 + (cluster_size * bb->rc_ratio / 100); 9701fd12bbSJon Paul Maloy } 9801fd12bbSJon Paul Maloy 99b06b281eSJon Paul Maloy /* tipc_bcbase_select_primary(): find a bearer with links to all destinations, 100b06b281eSJon Paul Maloy * if any, and make it primary bearer 101b06b281eSJon Paul Maloy */ 102b06b281eSJon Paul Maloy static void tipc_bcbase_select_primary(struct net *net) 103b06b281eSJon Paul Maloy { 104b06b281eSJon Paul Maloy struct tipc_bc_base *bb = tipc_bc_base(net); 105b06b281eSJon Paul Maloy int all_dests = tipc_link_bc_peers(bb->link); 1069999974aSJon Paul Maloy int i, mtu, prim; 107b06b281eSJon Paul Maloy 108b06b281eSJon Paul Maloy bb->primary_bearer = INVALID_BEARER_ID; 1099999974aSJon Paul Maloy bb->bcast_support = true; 110b06b281eSJon Paul Maloy 111b06b281eSJon Paul Maloy if (!all_dests) 112b06b281eSJon Paul Maloy return; 113b06b281eSJon Paul Maloy 114b06b281eSJon Paul Maloy for (i = 0; i < MAX_BEARERS; i++) { 115959e1781SJon Paul Maloy if (!bb->dests[i]) 116959e1781SJon Paul Maloy continue; 117959e1781SJon Paul Maloy 118959e1781SJon Paul Maloy mtu = tipc_bearer_mtu(net, i); 119959e1781SJon Paul Maloy if (mtu < tipc_link_mtu(bb->link)) 120959e1781SJon Paul Maloy tipc_link_set_mtu(bb->link, mtu); 1219999974aSJon Paul Maloy bb->bcast_support &= tipc_bearer_bcast_support(net, i); 122b06b281eSJon Paul Maloy if (bb->dests[i] < all_dests) 123b06b281eSJon Paul Maloy continue; 124b06b281eSJon Paul Maloy 125b06b281eSJon Paul Maloy bb->primary_bearer = i; 126b06b281eSJon Paul Maloy 127b06b281eSJon Paul Maloy /* Reduce risk that all nodes select same primary */ 128b06b281eSJon Paul Maloy if ((i ^ tipc_own_addr(net)) & 1) 129b06b281eSJon Paul Maloy break; 130b06b281eSJon Paul Maloy } 1319999974aSJon Paul Maloy prim = bb->primary_bearer; 1329999974aSJon Paul Maloy if (prim != INVALID_BEARER_ID) 1339999974aSJon Paul Maloy bb->bcast_support = tipc_bearer_bcast_support(net, prim); 134b06b281eSJon Paul Maloy } 135b06b281eSJon Paul Maloy 136b06b281eSJon Paul Maloy void tipc_bcast_inc_bearer_dst_cnt(struct net *net, int bearer_id) 137b06b281eSJon Paul Maloy { 138b06b281eSJon Paul Maloy struct tipc_bc_base *bb = tipc_bc_base(net); 139b06b281eSJon Paul Maloy 140b06b281eSJon Paul Maloy tipc_bcast_lock(net); 141b06b281eSJon Paul Maloy bb->dests[bearer_id]++; 142b06b281eSJon Paul Maloy tipc_bcbase_select_primary(net); 143b06b281eSJon Paul Maloy tipc_bcast_unlock(net); 144b06b281eSJon Paul Maloy } 145b06b281eSJon Paul Maloy 146b06b281eSJon Paul Maloy void tipc_bcast_dec_bearer_dst_cnt(struct net *net, int bearer_id) 147b06b281eSJon Paul Maloy { 148b06b281eSJon Paul Maloy struct tipc_bc_base *bb = tipc_bc_base(net); 149b06b281eSJon Paul Maloy 150b06b281eSJon Paul Maloy tipc_bcast_lock(net); 151b06b281eSJon Paul Maloy bb->dests[bearer_id]--; 152b06b281eSJon Paul Maloy tipc_bcbase_select_primary(net); 153b06b281eSJon Paul Maloy tipc_bcast_unlock(net); 154b06b281eSJon Paul Maloy } 155b06b281eSJon Paul Maloy 156b06b281eSJon Paul Maloy /* tipc_bcbase_xmit - broadcast a packet queue across one or more bearers 157b06b281eSJon Paul Maloy * 158b06b281eSJon Paul Maloy * Note that number of reachable destinations, as indicated in the dests[] 159b06b281eSJon Paul Maloy * array, may transitionally differ from the number of destinations indicated 160b06b281eSJon Paul Maloy * in each sent buffer. We can sustain this. Excess destination nodes will 161b06b281eSJon Paul Maloy * drop and never acknowledge the unexpected packets, and missing destinations 162b06b281eSJon Paul Maloy * will either require retransmission (if they are just about to be added to 163b06b281eSJon Paul Maloy * the bearer), or be removed from the buffer's 'ackers' counter (if they 164b06b281eSJon Paul Maloy * just went down) 165b06b281eSJon Paul Maloy */ 166b06b281eSJon Paul Maloy static void tipc_bcbase_xmit(struct net *net, struct sk_buff_head *xmitq) 167b06b281eSJon Paul Maloy { 168b06b281eSJon Paul Maloy int bearer_id; 169b06b281eSJon Paul Maloy struct tipc_bc_base *bb = tipc_bc_base(net); 170b06b281eSJon Paul Maloy struct sk_buff *skb, *_skb; 171b06b281eSJon Paul Maloy struct sk_buff_head _xmitq; 172b06b281eSJon Paul Maloy 173b06b281eSJon Paul Maloy if (skb_queue_empty(xmitq)) 174b06b281eSJon Paul Maloy return; 175b06b281eSJon Paul Maloy 176b06b281eSJon Paul Maloy /* The typical case: at least one bearer has links to all nodes */ 177b06b281eSJon Paul Maloy bearer_id = bb->primary_bearer; 178b06b281eSJon Paul Maloy if (bearer_id >= 0) { 179b06b281eSJon Paul Maloy tipc_bearer_bc_xmit(net, bearer_id, xmitq); 180b06b281eSJon Paul Maloy return; 181b06b281eSJon Paul Maloy } 182b06b281eSJon Paul Maloy 183b06b281eSJon Paul Maloy /* We have to transmit across all bearers */ 184b06b281eSJon Paul Maloy skb_queue_head_init(&_xmitq); 185b06b281eSJon Paul Maloy for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) { 186b06b281eSJon Paul Maloy if (!bb->dests[bearer_id]) 187b06b281eSJon Paul Maloy continue; 188b06b281eSJon Paul Maloy 189b06b281eSJon Paul Maloy skb_queue_walk(xmitq, skb) { 190b06b281eSJon Paul Maloy _skb = pskb_copy_for_clone(skb, GFP_ATOMIC); 191b06b281eSJon Paul Maloy if (!_skb) 192b06b281eSJon Paul Maloy break; 193b06b281eSJon Paul Maloy __skb_queue_tail(&_xmitq, _skb); 194b06b281eSJon Paul Maloy } 195b06b281eSJon Paul Maloy tipc_bearer_bc_xmit(net, bearer_id, &_xmitq); 196b06b281eSJon Paul Maloy } 197b06b281eSJon Paul Maloy __skb_queue_purge(xmitq); 198b06b281eSJon Paul Maloy __skb_queue_purge(&_xmitq); 199b06b281eSJon Paul Maloy } 200b06b281eSJon Paul Maloy 20101fd12bbSJon Paul Maloy static void tipc_bcast_select_xmit_method(struct net *net, int dests, 20201fd12bbSJon Paul Maloy struct tipc_mc_method *method) 20301fd12bbSJon Paul Maloy { 20401fd12bbSJon Paul Maloy struct tipc_bc_base *bb = tipc_bc_base(net); 20501fd12bbSJon Paul Maloy unsigned long exp = method->expires; 20601fd12bbSJon Paul Maloy 20701fd12bbSJon Paul Maloy /* Broadcast supported by used bearer/bearers? */ 20801fd12bbSJon Paul Maloy if (!bb->bcast_support) { 20901fd12bbSJon Paul Maloy method->rcast = true; 21001fd12bbSJon Paul Maloy return; 21101fd12bbSJon Paul Maloy } 21201fd12bbSJon Paul Maloy /* Any destinations which don't support replicast ? */ 21301fd12bbSJon Paul Maloy if (!bb->rcast_support) { 21401fd12bbSJon Paul Maloy method->rcast = false; 21501fd12bbSJon Paul Maloy return; 21601fd12bbSJon Paul Maloy } 21701fd12bbSJon Paul Maloy /* Can current method be changed ? */ 21801fd12bbSJon Paul Maloy method->expires = jiffies + TIPC_METHOD_EXPIRE; 21901fd12bbSJon Paul Maloy if (method->mandatory || time_before(jiffies, exp)) 22001fd12bbSJon Paul Maloy return; 22101fd12bbSJon Paul Maloy 22201fd12bbSJon Paul Maloy /* Determine method to use now */ 22301fd12bbSJon Paul Maloy method->rcast = dests <= bb->bc_threshold; 22401fd12bbSJon Paul Maloy } 22501fd12bbSJon Paul Maloy 226a853e4c6SJon Paul Maloy /* tipc_bcast_xmit - broadcast the buffer chain to all external nodes 227f2f9800dSYing Xue * @net: the applicable net namespace 228a853e4c6SJon Paul Maloy * @pkts: chain of buffers containing message 229a853e4c6SJon Paul Maloy * @cong_link_cnt: set to 1 if broadcast link is congested, otherwise 0 230365ad353SJon Paul Maloy * Consumes the buffer chain. 231a853e4c6SJon Paul Maloy * Returns 0 if success, otherwise errno: -EHOSTUNREACH,-EMSGSIZE 232078bec82SJon Paul Maloy */ 233a853e4c6SJon Paul Maloy static int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts, 234a853e4c6SJon Paul Maloy u16 *cong_link_cnt) 235078bec82SJon Paul Maloy { 2362f566124SJon Paul Maloy struct tipc_link *l = tipc_bc_sndlink(net); 237a853e4c6SJon Paul Maloy struct sk_buff_head xmitq; 238078bec82SJon Paul Maloy int rc = 0; 239078bec82SJon Paul Maloy 2403382605fSJon Maloy skb_queue_head_init(&xmitq); 2412f566124SJon Paul Maloy tipc_bcast_lock(net); 2422f566124SJon Paul Maloy if (tipc_link_bc_peers(l)) 243a853e4c6SJon Paul Maloy rc = tipc_link_xmit(l, pkts, &xmitq); 2442f566124SJon Paul Maloy tipc_bcast_unlock(net); 245a853e4c6SJon Paul Maloy tipc_bcbase_xmit(net, &xmitq); 246a853e4c6SJon Paul Maloy __skb_queue_purge(pkts); 247a853e4c6SJon Paul Maloy if (rc == -ELINKCONG) { 248a853e4c6SJon Paul Maloy *cong_link_cnt = 1; 249a853e4c6SJon Paul Maloy rc = 0; 250a853e4c6SJon Paul Maloy } 251cb1b7280SJon Paul Maloy return rc; 252cb1b7280SJon Paul Maloy } 25352666986SJon Paul Maloy 254a853e4c6SJon Paul Maloy /* tipc_rcast_xmit - replicate and send a message to given destination nodes 255a853e4c6SJon Paul Maloy * @net: the applicable net namespace 256a853e4c6SJon Paul Maloy * @pkts: chain of buffers containing message 257a853e4c6SJon Paul Maloy * @dests: list of destination nodes 258a853e4c6SJon Paul Maloy * @cong_link_cnt: returns number of congested links 259a853e4c6SJon Paul Maloy * @cong_links: returns identities of congested links 260a853e4c6SJon Paul Maloy * Returns 0 if success, otherwise errno 261a853e4c6SJon Paul Maloy */ 262a853e4c6SJon Paul Maloy static int tipc_rcast_xmit(struct net *net, struct sk_buff_head *pkts, 263a853e4c6SJon Paul Maloy struct tipc_nlist *dests, u16 *cong_link_cnt) 264a853e4c6SJon Paul Maloy { 265a80ae530SJon Maloy struct tipc_dest *dst, *tmp; 266a853e4c6SJon Paul Maloy struct sk_buff_head _pkts; 267a80ae530SJon Maloy u32 dnode, selector; 268a853e4c6SJon Paul Maloy 269a853e4c6SJon Paul Maloy selector = msg_link_selector(buf_msg(skb_peek(pkts))); 2703382605fSJon Maloy skb_queue_head_init(&_pkts); 271a853e4c6SJon Paul Maloy 272a80ae530SJon Maloy list_for_each_entry_safe(dst, tmp, &dests->list, list) { 273a80ae530SJon Maloy dnode = dst->node; 274a80ae530SJon Maloy if (!tipc_msg_pskb_copy(dnode, pkts, &_pkts)) 275a853e4c6SJon Paul Maloy return -ENOMEM; 276a853e4c6SJon Paul Maloy 277a853e4c6SJon Paul Maloy /* Any other return value than -ELINKCONG is ignored */ 278a80ae530SJon Maloy if (tipc_node_xmit(net, &_pkts, dnode, selector) == -ELINKCONG) 279a853e4c6SJon Paul Maloy (*cong_link_cnt)++; 280a853e4c6SJon Paul Maloy } 281a853e4c6SJon Paul Maloy return 0; 282a853e4c6SJon Paul Maloy } 283a853e4c6SJon Paul Maloy 284a853e4c6SJon Paul Maloy /* tipc_mcast_xmit - deliver message to indicated destination nodes 285a853e4c6SJon Paul Maloy * and to identified node local sockets 286a853e4c6SJon Paul Maloy * @net: the applicable net namespace 287a853e4c6SJon Paul Maloy * @pkts: chain of buffers containing message 28801fd12bbSJon Paul Maloy * @method: send method to be used 28901fd12bbSJon Paul Maloy * @dests: destination nodes for message. 290a853e4c6SJon Paul Maloy * @cong_link_cnt: returns number of encountered congested destination links 291a853e4c6SJon Paul Maloy * Consumes buffer chain. 292a853e4c6SJon Paul Maloy * Returns 0 if success, otherwise errno 293a853e4c6SJon Paul Maloy */ 294a853e4c6SJon Paul Maloy int tipc_mcast_xmit(struct net *net, struct sk_buff_head *pkts, 29501fd12bbSJon Paul Maloy struct tipc_mc_method *method, struct tipc_nlist *dests, 29601fd12bbSJon Paul Maloy u16 *cong_link_cnt) 297a853e4c6SJon Paul Maloy { 298a853e4c6SJon Paul Maloy struct sk_buff_head inputq, localq; 299a853e4c6SJon Paul Maloy int rc = 0; 300a853e4c6SJon Paul Maloy 301a853e4c6SJon Paul Maloy skb_queue_head_init(&inputq); 302a853e4c6SJon Paul Maloy skb_queue_head_init(&localq); 303a853e4c6SJon Paul Maloy 304a853e4c6SJon Paul Maloy /* Clone packets before they are consumed by next call */ 305a853e4c6SJon Paul Maloy if (dests->local && !tipc_msg_reassemble(pkts, &localq)) { 306a853e4c6SJon Paul Maloy rc = -ENOMEM; 307a853e4c6SJon Paul Maloy goto exit; 308a853e4c6SJon Paul Maloy } 30901fd12bbSJon Paul Maloy /* Send according to determined transmit method */ 310a853e4c6SJon Paul Maloy if (dests->remote) { 31101fd12bbSJon Paul Maloy tipc_bcast_select_xmit_method(net, dests->remote, method); 31201fd12bbSJon Paul Maloy if (method->rcast) 313a853e4c6SJon Paul Maloy rc = tipc_rcast_xmit(net, pkts, dests, cong_link_cnt); 314a853e4c6SJon Paul Maloy else 315a853e4c6SJon Paul Maloy rc = tipc_bcast_xmit(net, pkts, cong_link_cnt); 316a853e4c6SJon Paul Maloy } 317a853e4c6SJon Paul Maloy 318a853e4c6SJon Paul Maloy if (dests->local) 319a853e4c6SJon Paul Maloy tipc_sk_mcast_rcv(net, &localq, &inputq); 320a853e4c6SJon Paul Maloy exit: 32101fd12bbSJon Paul Maloy /* This queue should normally be empty by now */ 322a853e4c6SJon Paul Maloy __skb_queue_purge(pkts); 323365ad353SJon Paul Maloy return rc; 324078bec82SJon Paul Maloy } 32552666986SJon Paul Maloy 32652666986SJon Paul Maloy /* tipc_bcast_rcv - receive a broadcast packet, and deliver to rcv link 32752666986SJon Paul Maloy * 32852666986SJon Paul Maloy * RCU is locked, no other locks set 32952666986SJon Paul Maloy */ 33052666986SJon Paul Maloy int tipc_bcast_rcv(struct net *net, struct tipc_link *l, struct sk_buff *skb) 33152666986SJon Paul Maloy { 33252666986SJon Paul Maloy struct tipc_msg *hdr = buf_msg(skb); 33352666986SJon Paul Maloy struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq; 33452666986SJon Paul Maloy struct sk_buff_head xmitq; 33552666986SJon Paul Maloy int rc; 33652666986SJon Paul Maloy 33752666986SJon Paul Maloy __skb_queue_head_init(&xmitq); 33852666986SJon Paul Maloy 33952666986SJon Paul Maloy if (msg_mc_netid(hdr) != tipc_netid(net) || !tipc_link_is_up(l)) { 34052666986SJon Paul Maloy kfree_skb(skb); 34152666986SJon Paul Maloy return 0; 34252666986SJon Paul Maloy } 34352666986SJon Paul Maloy 34452666986SJon Paul Maloy tipc_bcast_lock(net); 34552666986SJon Paul Maloy if (msg_user(hdr) == BCAST_PROTOCOL) 34652666986SJon Paul Maloy rc = tipc_link_bc_nack_rcv(l, skb, &xmitq); 34752666986SJon Paul Maloy else 34852666986SJon Paul Maloy rc = tipc_link_rcv(l, skb, NULL); 34952666986SJon Paul Maloy tipc_bcast_unlock(net); 35052666986SJon Paul Maloy 351b06b281eSJon Paul Maloy tipc_bcbase_xmit(net, &xmitq); 35252666986SJon Paul Maloy 35352666986SJon Paul Maloy /* Any socket wakeup messages ? */ 35452666986SJon Paul Maloy if (!skb_queue_empty(inputq)) 35552666986SJon Paul Maloy tipc_sk_rcv(net, inputq); 35652666986SJon Paul Maloy 35752666986SJon Paul Maloy return rc; 35852666986SJon Paul Maloy } 35952666986SJon Paul Maloy 36052666986SJon Paul Maloy /* tipc_bcast_ack_rcv - receive and handle a broadcast acknowledge 36152666986SJon Paul Maloy * 36252666986SJon Paul Maloy * RCU is locked, no other locks set 36352666986SJon Paul Maloy */ 36406bd2b1eSJon Paul Maloy void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l, 36506bd2b1eSJon Paul Maloy struct tipc_msg *hdr) 36652666986SJon Paul Maloy { 36752666986SJon Paul Maloy struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq; 36806bd2b1eSJon Paul Maloy u16 acked = msg_bcast_ack(hdr); 36952666986SJon Paul Maloy struct sk_buff_head xmitq; 37052666986SJon Paul Maloy 37106bd2b1eSJon Paul Maloy /* Ignore bc acks sent by peer before bcast synch point was received */ 37206bd2b1eSJon Paul Maloy if (msg_bc_ack_invalid(hdr)) 37306bd2b1eSJon Paul Maloy return; 37406bd2b1eSJon Paul Maloy 37552666986SJon Paul Maloy __skb_queue_head_init(&xmitq); 37652666986SJon Paul Maloy 37752666986SJon Paul Maloy tipc_bcast_lock(net); 37852666986SJon Paul Maloy tipc_link_bc_ack_rcv(l, acked, &xmitq); 37952666986SJon Paul Maloy tipc_bcast_unlock(net); 38052666986SJon Paul Maloy 381b06b281eSJon Paul Maloy tipc_bcbase_xmit(net, &xmitq); 38252666986SJon Paul Maloy 38352666986SJon Paul Maloy /* Any socket wakeup messages ? */ 38452666986SJon Paul Maloy if (!skb_queue_empty(inputq)) 38552666986SJon Paul Maloy tipc_sk_rcv(net, inputq); 38652666986SJon Paul Maloy } 38752666986SJon Paul Maloy 38852666986SJon Paul Maloy /* tipc_bcast_synch_rcv - check and update rcv link with peer's send state 38952666986SJon Paul Maloy * 39052666986SJon Paul Maloy * RCU is locked, no other locks set 39152666986SJon Paul Maloy */ 39202d11ca2SJon Paul Maloy int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l, 39352666986SJon Paul Maloy struct tipc_msg *hdr) 39452666986SJon Paul Maloy { 39552666986SJon Paul Maloy struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq; 39652666986SJon Paul Maloy struct sk_buff_head xmitq; 39702d11ca2SJon Paul Maloy int rc = 0; 39852666986SJon Paul Maloy 39952666986SJon Paul Maloy __skb_queue_head_init(&xmitq); 40052666986SJon Paul Maloy 40152666986SJon Paul Maloy tipc_bcast_lock(net); 40206bd2b1eSJon Paul Maloy if (msg_type(hdr) != STATE_MSG) { 40306bd2b1eSJon Paul Maloy tipc_link_bc_init_rcv(l, hdr); 40406bd2b1eSJon Paul Maloy } else if (!msg_bc_ack_invalid(hdr)) { 40552666986SJon Paul Maloy tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr), &xmitq); 40602d11ca2SJon Paul Maloy rc = tipc_link_bc_sync_rcv(l, hdr, &xmitq); 40752666986SJon Paul Maloy } 40852666986SJon Paul Maloy tipc_bcast_unlock(net); 40952666986SJon Paul Maloy 410b06b281eSJon Paul Maloy tipc_bcbase_xmit(net, &xmitq); 41152666986SJon Paul Maloy 41252666986SJon Paul Maloy /* Any socket wakeup messages ? */ 41352666986SJon Paul Maloy if (!skb_queue_empty(inputq)) 41452666986SJon Paul Maloy tipc_sk_rcv(net, inputq); 41502d11ca2SJon Paul Maloy return rc; 41652666986SJon Paul Maloy } 41752666986SJon Paul Maloy 41852666986SJon Paul Maloy /* tipc_bcast_add_peer - add a peer node to broadcast link and bearer 41952666986SJon Paul Maloy * 42052666986SJon Paul Maloy * RCU is locked, node lock is set 42152666986SJon Paul Maloy */ 422b06b281eSJon Paul Maloy void tipc_bcast_add_peer(struct net *net, struct tipc_link *uc_l, 42352666986SJon Paul Maloy struct sk_buff_head *xmitq) 42452666986SJon Paul Maloy { 42552666986SJon Paul Maloy struct tipc_link *snd_l = tipc_bc_sndlink(net); 42652666986SJon Paul Maloy 427b06b281eSJon Paul Maloy tipc_bcast_lock(net); 42852666986SJon Paul Maloy tipc_link_add_bc_peer(snd_l, uc_l, xmitq); 429b06b281eSJon Paul Maloy tipc_bcbase_select_primary(net); 43001fd12bbSJon Paul Maloy tipc_bcbase_calc_bc_threshold(net); 431b06b281eSJon Paul Maloy tipc_bcast_unlock(net); 43252666986SJon Paul Maloy } 43352666986SJon Paul Maloy 43452666986SJon Paul Maloy /* tipc_bcast_remove_peer - remove a peer node from broadcast link and bearer 43552666986SJon Paul Maloy * 43652666986SJon Paul Maloy * RCU is locked, node lock is set 43752666986SJon Paul Maloy */ 438b06b281eSJon Paul Maloy void tipc_bcast_remove_peer(struct net *net, struct tipc_link *rcv_l) 43952666986SJon Paul Maloy { 44052666986SJon Paul Maloy struct tipc_link *snd_l = tipc_bc_sndlink(net); 441b06b281eSJon Paul Maloy struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq; 44252666986SJon Paul Maloy struct sk_buff_head xmitq; 44352666986SJon Paul Maloy 44452666986SJon Paul Maloy __skb_queue_head_init(&xmitq); 44552666986SJon Paul Maloy 446b06b281eSJon Paul Maloy tipc_bcast_lock(net); 44752666986SJon Paul Maloy tipc_link_remove_bc_peer(snd_l, rcv_l, &xmitq); 448b06b281eSJon Paul Maloy tipc_bcbase_select_primary(net); 44901fd12bbSJon Paul Maloy tipc_bcbase_calc_bc_threshold(net); 450b06b281eSJon Paul Maloy tipc_bcast_unlock(net); 45152666986SJon Paul Maloy 452b06b281eSJon Paul Maloy tipc_bcbase_xmit(net, &xmitq); 45352666986SJon Paul Maloy 45452666986SJon Paul Maloy /* Any socket wakeup messages ? */ 45552666986SJon Paul Maloy if (!skb_queue_empty(inputq)) 45652666986SJon Paul Maloy tipc_sk_rcv(net, inputq); 45752666986SJon Paul Maloy } 45852666986SJon Paul Maloy 4591da46568SYing Xue int tipc_bclink_reset_stats(struct net *net) 460b97bf3fdSPer Liden { 46138206d59SJon Paul Maloy struct tipc_link *l = tipc_bc_sndlink(net); 4621da46568SYing Xue 46338206d59SJon Paul Maloy if (!l) 464b97bf3fdSPer Liden return -ENOPROTOOPT; 465b97bf3fdSPer Liden 4662af5ae37SJon Paul Maloy tipc_bcast_lock(net); 46738206d59SJon Paul Maloy tipc_link_reset_stats(l); 4682af5ae37SJon Paul Maloy tipc_bcast_unlock(net); 4690e35fd5eSAllan Stephens return 0; 470b97bf3fdSPer Liden } 471b97bf3fdSPer Liden 4722af5ae37SJon Paul Maloy static int tipc_bc_link_set_queue_limits(struct net *net, u32 limit) 473b97bf3fdSPer Liden { 4742af5ae37SJon Paul Maloy struct tipc_link *l = tipc_bc_sndlink(net); 4751da46568SYing Xue 4762af5ae37SJon Paul Maloy if (!l) 477b97bf3fdSPer Liden return -ENOPROTOOPT; 47853387c4eSJon Paul Maloy if (limit < BCLINK_WIN_MIN) 47953387c4eSJon Paul Maloy limit = BCLINK_WIN_MIN; 48053387c4eSJon Paul Maloy if (limit > TIPC_MAX_LINK_WIN) 481b97bf3fdSPer Liden return -EINVAL; 4822af5ae37SJon Paul Maloy tipc_bcast_lock(net); 4832af5ae37SJon Paul Maloy tipc_link_set_queue_limits(l, limit); 4842af5ae37SJon Paul Maloy tipc_bcast_unlock(net); 4850e35fd5eSAllan Stephens return 0; 486b97bf3fdSPer Liden } 487b97bf3fdSPer Liden 488670f4f88SRichard Alpe int tipc_nl_bc_link_set(struct net *net, struct nlattr *attrs[]) 489670f4f88SRichard Alpe { 490670f4f88SRichard Alpe int err; 491670f4f88SRichard Alpe u32 win; 492670f4f88SRichard Alpe struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; 493670f4f88SRichard Alpe 494670f4f88SRichard Alpe if (!attrs[TIPC_NLA_LINK_PROP]) 495670f4f88SRichard Alpe return -EINVAL; 496670f4f88SRichard Alpe 497670f4f88SRichard Alpe err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_LINK_PROP], props); 498670f4f88SRichard Alpe if (err) 499670f4f88SRichard Alpe return err; 500670f4f88SRichard Alpe 501670f4f88SRichard Alpe if (!props[TIPC_NLA_PROP_WIN]) 502670f4f88SRichard Alpe return -EOPNOTSUPP; 503670f4f88SRichard Alpe 504670f4f88SRichard Alpe win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); 505670f4f88SRichard Alpe 5062af5ae37SJon Paul Maloy return tipc_bc_link_set_queue_limits(net, win); 507670f4f88SRichard Alpe } 508670f4f88SRichard Alpe 5096beb19a6SJon Paul Maloy int tipc_bcast_init(struct net *net) 510b97bf3fdSPer Liden { 51132301906SJon Paul Maloy struct tipc_net *tn = tipc_net(net); 51232301906SJon Paul Maloy struct tipc_bc_base *bb = NULL; 51332301906SJon Paul Maloy struct tipc_link *l = NULL; 5147f9f95d9SYing Xue 51532301906SJon Paul Maloy bb = kzalloc(sizeof(*bb), GFP_ATOMIC); 51632301906SJon Paul Maloy if (!bb) 51732301906SJon Paul Maloy goto enomem; 51832301906SJon Paul Maloy tn->bcbase = bb; 5190043550bSJon Paul Maloy spin_lock_init(&tipc_net(net)->bclock); 5205fd9fd63SJon Paul Maloy 521c72fa872SJon Paul Maloy if (!tipc_link_bc_create(net, 0, 0, 5224c94cc2dSJon Maloy FB_MTU, 52332301906SJon Paul Maloy BCLINK_WIN_DEFAULT, 524fd556f20SJon Paul Maloy 0, 52532301906SJon Paul Maloy &bb->inputq, 5262af5ae37SJon Paul Maloy NULL, 52752666986SJon Paul Maloy NULL, 52832301906SJon Paul Maloy &l)) 52932301906SJon Paul Maloy goto enomem; 53032301906SJon Paul Maloy bb->link = l; 53132301906SJon Paul Maloy tn->bcl = l; 53201fd12bbSJon Paul Maloy bb->rc_ratio = 25; 53301fd12bbSJon Paul Maloy bb->rcast_support = true; 534eb8b00f5SYing Xue return 0; 53532301906SJon Paul Maloy enomem: 53632301906SJon Paul Maloy kfree(bb); 53732301906SJon Paul Maloy kfree(l); 53832301906SJon Paul Maloy return -ENOMEM; 539b97bf3fdSPer Liden } 540b97bf3fdSPer Liden 5416beb19a6SJon Paul Maloy void tipc_bcast_stop(struct net *net) 542b97bf3fdSPer Liden { 5437f9f95d9SYing Xue struct tipc_net *tn = net_generic(net, tipc_net_id); 5447f9f95d9SYing Xue 545eb8b00f5SYing Xue synchronize_net(); 5466beb19a6SJon Paul Maloy kfree(tn->bcbase); 54732301906SJon Paul Maloy kfree(tn->bcl); 548b97bf3fdSPer Liden } 5492ae0b8afSJon Paul Maloy 5502ae0b8afSJon Paul Maloy void tipc_nlist_init(struct tipc_nlist *nl, u32 self) 5512ae0b8afSJon Paul Maloy { 5522ae0b8afSJon Paul Maloy memset(nl, 0, sizeof(*nl)); 5532ae0b8afSJon Paul Maloy INIT_LIST_HEAD(&nl->list); 5542ae0b8afSJon Paul Maloy nl->self = self; 5552ae0b8afSJon Paul Maloy } 5562ae0b8afSJon Paul Maloy 5572ae0b8afSJon Paul Maloy void tipc_nlist_add(struct tipc_nlist *nl, u32 node) 5582ae0b8afSJon Paul Maloy { 5592ae0b8afSJon Paul Maloy if (node == nl->self) 5602ae0b8afSJon Paul Maloy nl->local = true; 561a80ae530SJon Maloy else if (tipc_dest_push(&nl->list, node, 0)) 5622ae0b8afSJon Paul Maloy nl->remote++; 5632ae0b8afSJon Paul Maloy } 5642ae0b8afSJon Paul Maloy 5652ae0b8afSJon Paul Maloy void tipc_nlist_del(struct tipc_nlist *nl, u32 node) 5662ae0b8afSJon Paul Maloy { 5672ae0b8afSJon Paul Maloy if (node == nl->self) 5682ae0b8afSJon Paul Maloy nl->local = false; 569a80ae530SJon Maloy else if (tipc_dest_del(&nl->list, node, 0)) 5702ae0b8afSJon Paul Maloy nl->remote--; 5712ae0b8afSJon Paul Maloy } 5722ae0b8afSJon Paul Maloy 5732ae0b8afSJon Paul Maloy void tipc_nlist_purge(struct tipc_nlist *nl) 5742ae0b8afSJon Paul Maloy { 575a80ae530SJon Maloy tipc_dest_list_purge(&nl->list); 5762ae0b8afSJon Paul Maloy nl->remote = 0; 5772ae0b8afSJon Paul Maloy nl->local = 0; 5782ae0b8afSJon Paul Maloy } 579