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