162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * net/tipc/group.c: TIPC group messaging code 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2017, Ericsson AB 562306a36Sopenharmony_ci * Copyright (c) 2020, Red Hat Inc 662306a36Sopenharmony_ci * All rights reserved. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 962306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 1262306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 1362306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 1462306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 1562306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 1662306a36Sopenharmony_ci * 3. Neither the names of the copyright holders nor the names of its 1762306a36Sopenharmony_ci * contributors may be used to endorse or promote products derived from 1862306a36Sopenharmony_ci * this software without specific prior written permission. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 2162306a36Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free 2262306a36Sopenharmony_ci * Software Foundation. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2562306a36Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2662306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2762306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2862306a36Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2962306a36Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3062306a36Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3162306a36Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3262306a36Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3362306a36Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3462306a36Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include "core.h" 3862306a36Sopenharmony_ci#include "addr.h" 3962306a36Sopenharmony_ci#include "group.h" 4062306a36Sopenharmony_ci#include "bcast.h" 4162306a36Sopenharmony_ci#include "topsrv.h" 4262306a36Sopenharmony_ci#include "msg.h" 4362306a36Sopenharmony_ci#include "socket.h" 4462306a36Sopenharmony_ci#include "node.h" 4562306a36Sopenharmony_ci#include "name_table.h" 4662306a36Sopenharmony_ci#include "subscr.h" 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define ADV_UNIT (((MAX_MSG_SIZE + MAX_H_SIZE) / FLOWCTL_BLK_SZ) + 1) 4962306a36Sopenharmony_ci#define ADV_IDLE ADV_UNIT 5062306a36Sopenharmony_ci#define ADV_ACTIVE (ADV_UNIT * 12) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cienum mbr_state { 5362306a36Sopenharmony_ci MBR_JOINING, 5462306a36Sopenharmony_ci MBR_PUBLISHED, 5562306a36Sopenharmony_ci MBR_JOINED, 5662306a36Sopenharmony_ci MBR_PENDING, 5762306a36Sopenharmony_ci MBR_ACTIVE, 5862306a36Sopenharmony_ci MBR_RECLAIMING, 5962306a36Sopenharmony_ci MBR_REMITTED, 6062306a36Sopenharmony_ci MBR_LEAVING 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistruct tipc_member { 6462306a36Sopenharmony_ci struct rb_node tree_node; 6562306a36Sopenharmony_ci struct list_head list; 6662306a36Sopenharmony_ci struct list_head small_win; 6762306a36Sopenharmony_ci struct sk_buff_head deferredq; 6862306a36Sopenharmony_ci struct tipc_group *group; 6962306a36Sopenharmony_ci u32 node; 7062306a36Sopenharmony_ci u32 port; 7162306a36Sopenharmony_ci u32 instance; 7262306a36Sopenharmony_ci enum mbr_state state; 7362306a36Sopenharmony_ci u16 advertised; 7462306a36Sopenharmony_ci u16 window; 7562306a36Sopenharmony_ci u16 bc_rcv_nxt; 7662306a36Sopenharmony_ci u16 bc_syncpt; 7762306a36Sopenharmony_ci u16 bc_acked; 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistruct tipc_group { 8162306a36Sopenharmony_ci struct rb_root members; 8262306a36Sopenharmony_ci struct list_head small_win; 8362306a36Sopenharmony_ci struct list_head pending; 8462306a36Sopenharmony_ci struct list_head active; 8562306a36Sopenharmony_ci struct tipc_nlist dests; 8662306a36Sopenharmony_ci struct net *net; 8762306a36Sopenharmony_ci int subid; 8862306a36Sopenharmony_ci u32 type; 8962306a36Sopenharmony_ci u32 instance; 9062306a36Sopenharmony_ci u32 scope; 9162306a36Sopenharmony_ci u32 portid; 9262306a36Sopenharmony_ci u16 member_cnt; 9362306a36Sopenharmony_ci u16 active_cnt; 9462306a36Sopenharmony_ci u16 max_active; 9562306a36Sopenharmony_ci u16 bc_snd_nxt; 9662306a36Sopenharmony_ci u16 bc_ackers; 9762306a36Sopenharmony_ci bool *open; 9862306a36Sopenharmony_ci bool loopback; 9962306a36Sopenharmony_ci bool events; 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m, 10362306a36Sopenharmony_ci int mtyp, struct sk_buff_head *xmitq); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void tipc_group_open(struct tipc_member *m, bool *wakeup) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci *wakeup = false; 10862306a36Sopenharmony_ci if (list_empty(&m->small_win)) 10962306a36Sopenharmony_ci return; 11062306a36Sopenharmony_ci list_del_init(&m->small_win); 11162306a36Sopenharmony_ci *m->group->open = true; 11262306a36Sopenharmony_ci *wakeup = true; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic void tipc_group_decr_active(struct tipc_group *grp, 11662306a36Sopenharmony_ci struct tipc_member *m) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci if (m->state == MBR_ACTIVE || m->state == MBR_RECLAIMING || 11962306a36Sopenharmony_ci m->state == MBR_REMITTED) 12062306a36Sopenharmony_ci grp->active_cnt--; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int tipc_group_rcvbuf_limit(struct tipc_group *grp) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci int max_active, active_pool, idle_pool; 12662306a36Sopenharmony_ci int mcnt = grp->member_cnt + 1; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* Limit simultaneous reception from other members */ 12962306a36Sopenharmony_ci max_active = min(mcnt / 8, 64); 13062306a36Sopenharmony_ci max_active = max(max_active, 16); 13162306a36Sopenharmony_ci grp->max_active = max_active; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* Reserve blocks for active and idle members */ 13462306a36Sopenharmony_ci active_pool = max_active * ADV_ACTIVE; 13562306a36Sopenharmony_ci idle_pool = (mcnt - max_active) * ADV_IDLE; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Scale to bytes, considering worst-case truesize/msgsize ratio */ 13862306a36Sopenharmony_ci return (active_pool + idle_pool) * FLOWCTL_BLK_SZ * 4; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ciu16 tipc_group_bc_snd_nxt(struct tipc_group *grp) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci return grp->bc_snd_nxt; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic bool tipc_group_is_receiver(struct tipc_member *m) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci return m && m->state != MBR_JOINING && m->state != MBR_LEAVING; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic bool tipc_group_is_sender(struct tipc_member *m) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci return m && m->state != MBR_JOINING && m->state != MBR_PUBLISHED; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ciu32 tipc_group_exclude(struct tipc_group *grp) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci if (!grp->loopback) 15962306a36Sopenharmony_ci return grp->portid; 16062306a36Sopenharmony_ci return 0; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistruct tipc_group *tipc_group_create(struct net *net, u32 portid, 16462306a36Sopenharmony_ci struct tipc_group_req *mreq, 16562306a36Sopenharmony_ci bool *group_is_open) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci u32 filter = TIPC_SUB_PORTS | TIPC_SUB_NO_STATUS; 16862306a36Sopenharmony_ci bool global = mreq->scope != TIPC_NODE_SCOPE; 16962306a36Sopenharmony_ci struct tipc_group *grp; 17062306a36Sopenharmony_ci u32 type = mreq->type; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci grp = kzalloc(sizeof(*grp), GFP_ATOMIC); 17362306a36Sopenharmony_ci if (!grp) 17462306a36Sopenharmony_ci return NULL; 17562306a36Sopenharmony_ci tipc_nlist_init(&grp->dests, tipc_own_addr(net)); 17662306a36Sopenharmony_ci INIT_LIST_HEAD(&grp->small_win); 17762306a36Sopenharmony_ci INIT_LIST_HEAD(&grp->active); 17862306a36Sopenharmony_ci INIT_LIST_HEAD(&grp->pending); 17962306a36Sopenharmony_ci grp->members = RB_ROOT; 18062306a36Sopenharmony_ci grp->net = net; 18162306a36Sopenharmony_ci grp->portid = portid; 18262306a36Sopenharmony_ci grp->type = type; 18362306a36Sopenharmony_ci grp->instance = mreq->instance; 18462306a36Sopenharmony_ci grp->scope = mreq->scope; 18562306a36Sopenharmony_ci grp->loopback = mreq->flags & TIPC_GROUP_LOOPBACK; 18662306a36Sopenharmony_ci grp->events = mreq->flags & TIPC_GROUP_MEMBER_EVTS; 18762306a36Sopenharmony_ci grp->open = group_is_open; 18862306a36Sopenharmony_ci *grp->open = false; 18962306a36Sopenharmony_ci filter |= global ? TIPC_SUB_CLUSTER_SCOPE : TIPC_SUB_NODE_SCOPE; 19062306a36Sopenharmony_ci if (tipc_topsrv_kern_subscr(net, portid, type, 0, ~0, 19162306a36Sopenharmony_ci filter, &grp->subid)) 19262306a36Sopenharmony_ci return grp; 19362306a36Sopenharmony_ci kfree(grp); 19462306a36Sopenharmony_ci return NULL; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_civoid tipc_group_join(struct net *net, struct tipc_group *grp, int *sk_rcvbuf) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci struct rb_root *tree = &grp->members; 20062306a36Sopenharmony_ci struct tipc_member *m, *tmp; 20162306a36Sopenharmony_ci struct sk_buff_head xmitq; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci __skb_queue_head_init(&xmitq); 20462306a36Sopenharmony_ci rbtree_postorder_for_each_entry_safe(m, tmp, tree, tree_node) { 20562306a36Sopenharmony_ci tipc_group_proto_xmit(grp, m, GRP_JOIN_MSG, &xmitq); 20662306a36Sopenharmony_ci tipc_group_update_member(m, 0); 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci tipc_node_distr_xmit(net, &xmitq); 20962306a36Sopenharmony_ci *sk_rcvbuf = tipc_group_rcvbuf_limit(grp); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_civoid tipc_group_delete(struct net *net, struct tipc_group *grp) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct rb_root *tree = &grp->members; 21562306a36Sopenharmony_ci struct tipc_member *m, *tmp; 21662306a36Sopenharmony_ci struct sk_buff_head xmitq; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci __skb_queue_head_init(&xmitq); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci rbtree_postorder_for_each_entry_safe(m, tmp, tree, tree_node) { 22162306a36Sopenharmony_ci tipc_group_proto_xmit(grp, m, GRP_LEAVE_MSG, &xmitq); 22262306a36Sopenharmony_ci __skb_queue_purge(&m->deferredq); 22362306a36Sopenharmony_ci list_del(&m->list); 22462306a36Sopenharmony_ci kfree(m); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci tipc_node_distr_xmit(net, &xmitq); 22762306a36Sopenharmony_ci tipc_nlist_purge(&grp->dests); 22862306a36Sopenharmony_ci tipc_topsrv_kern_unsubscr(net, grp->subid); 22962306a36Sopenharmony_ci kfree(grp); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic struct tipc_member *tipc_group_find_member(struct tipc_group *grp, 23362306a36Sopenharmony_ci u32 node, u32 port) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct rb_node *n = grp->members.rb_node; 23662306a36Sopenharmony_ci u64 nkey, key = (u64)node << 32 | port; 23762306a36Sopenharmony_ci struct tipc_member *m; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci while (n) { 24062306a36Sopenharmony_ci m = container_of(n, struct tipc_member, tree_node); 24162306a36Sopenharmony_ci nkey = (u64)m->node << 32 | m->port; 24262306a36Sopenharmony_ci if (key < nkey) 24362306a36Sopenharmony_ci n = n->rb_left; 24462306a36Sopenharmony_ci else if (key > nkey) 24562306a36Sopenharmony_ci n = n->rb_right; 24662306a36Sopenharmony_ci else 24762306a36Sopenharmony_ci return m; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci return NULL; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic struct tipc_member *tipc_group_find_dest(struct tipc_group *grp, 25362306a36Sopenharmony_ci u32 node, u32 port) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct tipc_member *m; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci m = tipc_group_find_member(grp, node, port); 25862306a36Sopenharmony_ci if (m && tipc_group_is_receiver(m)) 25962306a36Sopenharmony_ci return m; 26062306a36Sopenharmony_ci return NULL; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic struct tipc_member *tipc_group_find_node(struct tipc_group *grp, 26462306a36Sopenharmony_ci u32 node) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct tipc_member *m; 26762306a36Sopenharmony_ci struct rb_node *n; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci for (n = rb_first(&grp->members); n; n = rb_next(n)) { 27062306a36Sopenharmony_ci m = container_of(n, struct tipc_member, tree_node); 27162306a36Sopenharmony_ci if (m->node == node) 27262306a36Sopenharmony_ci return m; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci return NULL; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic int tipc_group_add_to_tree(struct tipc_group *grp, 27862306a36Sopenharmony_ci struct tipc_member *m) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci u64 nkey, key = (u64)m->node << 32 | m->port; 28162306a36Sopenharmony_ci struct rb_node **n, *parent = NULL; 28262306a36Sopenharmony_ci struct tipc_member *tmp; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci n = &grp->members.rb_node; 28562306a36Sopenharmony_ci while (*n) { 28662306a36Sopenharmony_ci tmp = container_of(*n, struct tipc_member, tree_node); 28762306a36Sopenharmony_ci parent = *n; 28862306a36Sopenharmony_ci tmp = container_of(parent, struct tipc_member, tree_node); 28962306a36Sopenharmony_ci nkey = (u64)tmp->node << 32 | tmp->port; 29062306a36Sopenharmony_ci if (key < nkey) 29162306a36Sopenharmony_ci n = &(*n)->rb_left; 29262306a36Sopenharmony_ci else if (key > nkey) 29362306a36Sopenharmony_ci n = &(*n)->rb_right; 29462306a36Sopenharmony_ci else 29562306a36Sopenharmony_ci return -EEXIST; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci rb_link_node(&m->tree_node, parent, n); 29862306a36Sopenharmony_ci rb_insert_color(&m->tree_node, &grp->members); 29962306a36Sopenharmony_ci return 0; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic struct tipc_member *tipc_group_create_member(struct tipc_group *grp, 30362306a36Sopenharmony_ci u32 node, u32 port, 30462306a36Sopenharmony_ci u32 instance, int state) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci struct tipc_member *m; 30762306a36Sopenharmony_ci int ret; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci m = kzalloc(sizeof(*m), GFP_ATOMIC); 31062306a36Sopenharmony_ci if (!m) 31162306a36Sopenharmony_ci return NULL; 31262306a36Sopenharmony_ci INIT_LIST_HEAD(&m->list); 31362306a36Sopenharmony_ci INIT_LIST_HEAD(&m->small_win); 31462306a36Sopenharmony_ci __skb_queue_head_init(&m->deferredq); 31562306a36Sopenharmony_ci m->group = grp; 31662306a36Sopenharmony_ci m->node = node; 31762306a36Sopenharmony_ci m->port = port; 31862306a36Sopenharmony_ci m->instance = instance; 31962306a36Sopenharmony_ci m->bc_acked = grp->bc_snd_nxt - 1; 32062306a36Sopenharmony_ci ret = tipc_group_add_to_tree(grp, m); 32162306a36Sopenharmony_ci if (ret < 0) { 32262306a36Sopenharmony_ci kfree(m); 32362306a36Sopenharmony_ci return NULL; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci grp->member_cnt++; 32662306a36Sopenharmony_ci tipc_nlist_add(&grp->dests, m->node); 32762306a36Sopenharmony_ci m->state = state; 32862306a36Sopenharmony_ci return m; 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_civoid tipc_group_add_member(struct tipc_group *grp, u32 node, 33262306a36Sopenharmony_ci u32 port, u32 instance) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci tipc_group_create_member(grp, node, port, instance, MBR_PUBLISHED); 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic void tipc_group_delete_member(struct tipc_group *grp, 33862306a36Sopenharmony_ci struct tipc_member *m) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci rb_erase(&m->tree_node, &grp->members); 34162306a36Sopenharmony_ci grp->member_cnt--; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* Check if we were waiting for replicast ack from this member */ 34462306a36Sopenharmony_ci if (grp->bc_ackers && less(m->bc_acked, grp->bc_snd_nxt - 1)) 34562306a36Sopenharmony_ci grp->bc_ackers--; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci list_del_init(&m->list); 34862306a36Sopenharmony_ci list_del_init(&m->small_win); 34962306a36Sopenharmony_ci tipc_group_decr_active(grp, m); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* If last member on a node, remove node from dest list */ 35262306a36Sopenharmony_ci if (!tipc_group_find_node(grp, m->node)) 35362306a36Sopenharmony_ci tipc_nlist_del(&grp->dests, m->node); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci kfree(m); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistruct tipc_nlist *tipc_group_dests(struct tipc_group *grp) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci return &grp->dests; 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_civoid tipc_group_self(struct tipc_group *grp, struct tipc_service_range *seq, 36462306a36Sopenharmony_ci int *scope) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci seq->type = grp->type; 36762306a36Sopenharmony_ci seq->lower = grp->instance; 36862306a36Sopenharmony_ci seq->upper = grp->instance; 36962306a36Sopenharmony_ci *scope = grp->scope; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_civoid tipc_group_update_member(struct tipc_member *m, int len) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci struct tipc_group *grp = m->group; 37562306a36Sopenharmony_ci struct tipc_member *_m, *tmp; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (!tipc_group_is_receiver(m)) 37862306a36Sopenharmony_ci return; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci m->window -= len; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (m->window >= ADV_IDLE) 38362306a36Sopenharmony_ci return; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci list_del_init(&m->small_win); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* Sort member into small_window members' list */ 38862306a36Sopenharmony_ci list_for_each_entry_safe(_m, tmp, &grp->small_win, small_win) { 38962306a36Sopenharmony_ci if (_m->window > m->window) 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci list_add_tail(&m->small_win, &_m->small_win); 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_civoid tipc_group_update_bc_members(struct tipc_group *grp, int len, bool ack) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci u16 prev = grp->bc_snd_nxt - 1; 39862306a36Sopenharmony_ci struct tipc_member *m; 39962306a36Sopenharmony_ci struct rb_node *n; 40062306a36Sopenharmony_ci u16 ackers = 0; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci for (n = rb_first(&grp->members); n; n = rb_next(n)) { 40362306a36Sopenharmony_ci m = container_of(n, struct tipc_member, tree_node); 40462306a36Sopenharmony_ci if (tipc_group_is_receiver(m)) { 40562306a36Sopenharmony_ci tipc_group_update_member(m, len); 40662306a36Sopenharmony_ci m->bc_acked = prev; 40762306a36Sopenharmony_ci ackers++; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* Mark number of acknowledges to expect, if any */ 41262306a36Sopenharmony_ci if (ack) 41362306a36Sopenharmony_ci grp->bc_ackers = ackers; 41462306a36Sopenharmony_ci grp->bc_snd_nxt++; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cibool tipc_group_cong(struct tipc_group *grp, u32 dnode, u32 dport, 41862306a36Sopenharmony_ci int len, struct tipc_member **mbr) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci struct sk_buff_head xmitq; 42162306a36Sopenharmony_ci struct tipc_member *m; 42262306a36Sopenharmony_ci int adv, state; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci m = tipc_group_find_dest(grp, dnode, dport); 42562306a36Sopenharmony_ci if (!tipc_group_is_receiver(m)) { 42662306a36Sopenharmony_ci *mbr = NULL; 42762306a36Sopenharmony_ci return false; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci *mbr = m; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (m->window >= len) 43262306a36Sopenharmony_ci return false; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci *grp->open = false; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci /* If not fully advertised, do it now to prevent mutual blocking */ 43762306a36Sopenharmony_ci adv = m->advertised; 43862306a36Sopenharmony_ci state = m->state; 43962306a36Sopenharmony_ci if (state == MBR_JOINED && adv == ADV_IDLE) 44062306a36Sopenharmony_ci return true; 44162306a36Sopenharmony_ci if (state == MBR_ACTIVE && adv == ADV_ACTIVE) 44262306a36Sopenharmony_ci return true; 44362306a36Sopenharmony_ci if (state == MBR_PENDING && adv == ADV_IDLE) 44462306a36Sopenharmony_ci return true; 44562306a36Sopenharmony_ci __skb_queue_head_init(&xmitq); 44662306a36Sopenharmony_ci tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, &xmitq); 44762306a36Sopenharmony_ci tipc_node_distr_xmit(grp->net, &xmitq); 44862306a36Sopenharmony_ci return true; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cibool tipc_group_bc_cong(struct tipc_group *grp, int len) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct tipc_member *m = NULL; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* If prev bcast was replicast, reject until all receivers have acked */ 45662306a36Sopenharmony_ci if (grp->bc_ackers) { 45762306a36Sopenharmony_ci *grp->open = false; 45862306a36Sopenharmony_ci return true; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci if (list_empty(&grp->small_win)) 46162306a36Sopenharmony_ci return false; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci m = list_first_entry(&grp->small_win, struct tipc_member, small_win); 46462306a36Sopenharmony_ci if (m->window >= len) 46562306a36Sopenharmony_ci return false; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci return tipc_group_cong(grp, m->node, m->port, len, &m); 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci/* tipc_group_sort_msg() - sort msg into queue by bcast sequence number 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_cistatic void tipc_group_sort_msg(struct sk_buff *skb, struct sk_buff_head *defq) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci struct tipc_msg *_hdr, *hdr = buf_msg(skb); 47562306a36Sopenharmony_ci u16 bc_seqno = msg_grp_bc_seqno(hdr); 47662306a36Sopenharmony_ci struct sk_buff *_skb, *tmp; 47762306a36Sopenharmony_ci int mtyp = msg_type(hdr); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* Bcast/mcast may be bypassed by ucast or other bcast, - sort it in */ 48062306a36Sopenharmony_ci if (mtyp == TIPC_GRP_BCAST_MSG || mtyp == TIPC_GRP_MCAST_MSG) { 48162306a36Sopenharmony_ci skb_queue_walk_safe(defq, _skb, tmp) { 48262306a36Sopenharmony_ci _hdr = buf_msg(_skb); 48362306a36Sopenharmony_ci if (!less(bc_seqno, msg_grp_bc_seqno(_hdr))) 48462306a36Sopenharmony_ci continue; 48562306a36Sopenharmony_ci __skb_queue_before(defq, _skb, skb); 48662306a36Sopenharmony_ci return; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci /* Bcast was not bypassed, - add to tail */ 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci /* Unicasts are never bypassed, - always add to tail */ 49162306a36Sopenharmony_ci __skb_queue_tail(defq, skb); 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci/* tipc_group_filter_msg() - determine if we should accept arriving message 49562306a36Sopenharmony_ci */ 49662306a36Sopenharmony_civoid tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq, 49762306a36Sopenharmony_ci struct sk_buff_head *xmitq) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci struct sk_buff *skb = __skb_dequeue(inputq); 50062306a36Sopenharmony_ci bool ack, deliver, update, leave = false; 50162306a36Sopenharmony_ci struct sk_buff_head *defq; 50262306a36Sopenharmony_ci struct tipc_member *m; 50362306a36Sopenharmony_ci struct tipc_msg *hdr; 50462306a36Sopenharmony_ci u32 node, port; 50562306a36Sopenharmony_ci int mtyp, blks; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (!skb) 50862306a36Sopenharmony_ci return; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci hdr = buf_msg(skb); 51162306a36Sopenharmony_ci node = msg_orignode(hdr); 51262306a36Sopenharmony_ci port = msg_origport(hdr); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (!msg_in_group(hdr)) 51562306a36Sopenharmony_ci goto drop; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci m = tipc_group_find_member(grp, node, port); 51862306a36Sopenharmony_ci if (!tipc_group_is_sender(m)) 51962306a36Sopenharmony_ci goto drop; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (less(msg_grp_bc_seqno(hdr), m->bc_rcv_nxt)) 52262306a36Sopenharmony_ci goto drop; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci TIPC_SKB_CB(skb)->orig_member = m->instance; 52562306a36Sopenharmony_ci defq = &m->deferredq; 52662306a36Sopenharmony_ci tipc_group_sort_msg(skb, defq); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci while ((skb = skb_peek(defq))) { 52962306a36Sopenharmony_ci hdr = buf_msg(skb); 53062306a36Sopenharmony_ci mtyp = msg_type(hdr); 53162306a36Sopenharmony_ci blks = msg_blocks(hdr); 53262306a36Sopenharmony_ci deliver = true; 53362306a36Sopenharmony_ci ack = false; 53462306a36Sopenharmony_ci update = false; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (more(msg_grp_bc_seqno(hdr), m->bc_rcv_nxt)) 53762306a36Sopenharmony_ci break; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /* Decide what to do with message */ 54062306a36Sopenharmony_ci switch (mtyp) { 54162306a36Sopenharmony_ci case TIPC_GRP_MCAST_MSG: 54262306a36Sopenharmony_ci if (msg_nameinst(hdr) != grp->instance) { 54362306a36Sopenharmony_ci update = true; 54462306a36Sopenharmony_ci deliver = false; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci fallthrough; 54762306a36Sopenharmony_ci case TIPC_GRP_BCAST_MSG: 54862306a36Sopenharmony_ci m->bc_rcv_nxt++; 54962306a36Sopenharmony_ci ack = msg_grp_bc_ack_req(hdr); 55062306a36Sopenharmony_ci break; 55162306a36Sopenharmony_ci case TIPC_GRP_UCAST_MSG: 55262306a36Sopenharmony_ci break; 55362306a36Sopenharmony_ci case TIPC_GRP_MEMBER_EVT: 55462306a36Sopenharmony_ci if (m->state == MBR_LEAVING) 55562306a36Sopenharmony_ci leave = true; 55662306a36Sopenharmony_ci if (!grp->events) 55762306a36Sopenharmony_ci deliver = false; 55862306a36Sopenharmony_ci break; 55962306a36Sopenharmony_ci default: 56062306a36Sopenharmony_ci break; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* Execute decisions */ 56462306a36Sopenharmony_ci __skb_dequeue(defq); 56562306a36Sopenharmony_ci if (deliver) 56662306a36Sopenharmony_ci __skb_queue_tail(inputq, skb); 56762306a36Sopenharmony_ci else 56862306a36Sopenharmony_ci kfree_skb(skb); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (ack) 57162306a36Sopenharmony_ci tipc_group_proto_xmit(grp, m, GRP_ACK_MSG, xmitq); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (leave) { 57462306a36Sopenharmony_ci __skb_queue_purge(defq); 57562306a36Sopenharmony_ci tipc_group_delete_member(grp, m); 57662306a36Sopenharmony_ci break; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci if (!update) 57962306a36Sopenharmony_ci continue; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci tipc_group_update_rcv_win(grp, blks, node, port, xmitq); 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci return; 58462306a36Sopenharmony_cidrop: 58562306a36Sopenharmony_ci kfree_skb(skb); 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_civoid tipc_group_update_rcv_win(struct tipc_group *grp, int blks, u32 node, 58962306a36Sopenharmony_ci u32 port, struct sk_buff_head *xmitq) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci struct list_head *active = &grp->active; 59262306a36Sopenharmony_ci int max_active = grp->max_active; 59362306a36Sopenharmony_ci int reclaim_limit = max_active * 3 / 4; 59462306a36Sopenharmony_ci int active_cnt = grp->active_cnt; 59562306a36Sopenharmony_ci struct tipc_member *m, *rm, *pm; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci m = tipc_group_find_member(grp, node, port); 59862306a36Sopenharmony_ci if (!m) 59962306a36Sopenharmony_ci return; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci m->advertised -= blks; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci switch (m->state) { 60462306a36Sopenharmony_ci case MBR_JOINED: 60562306a36Sopenharmony_ci /* First, decide if member can go active */ 60662306a36Sopenharmony_ci if (active_cnt <= max_active) { 60762306a36Sopenharmony_ci m->state = MBR_ACTIVE; 60862306a36Sopenharmony_ci list_add_tail(&m->list, active); 60962306a36Sopenharmony_ci grp->active_cnt++; 61062306a36Sopenharmony_ci tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq); 61162306a36Sopenharmony_ci } else { 61262306a36Sopenharmony_ci m->state = MBR_PENDING; 61362306a36Sopenharmony_ci list_add_tail(&m->list, &grp->pending); 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (active_cnt < reclaim_limit) 61762306a36Sopenharmony_ci break; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* Reclaim from oldest active member, if possible */ 62062306a36Sopenharmony_ci if (!list_empty(active)) { 62162306a36Sopenharmony_ci rm = list_first_entry(active, struct tipc_member, list); 62262306a36Sopenharmony_ci rm->state = MBR_RECLAIMING; 62362306a36Sopenharmony_ci list_del_init(&rm->list); 62462306a36Sopenharmony_ci tipc_group_proto_xmit(grp, rm, GRP_RECLAIM_MSG, xmitq); 62562306a36Sopenharmony_ci break; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci /* Nobody to reclaim from; - revert oldest pending to JOINED */ 62862306a36Sopenharmony_ci pm = list_first_entry(&grp->pending, struct tipc_member, list); 62962306a36Sopenharmony_ci list_del_init(&pm->list); 63062306a36Sopenharmony_ci pm->state = MBR_JOINED; 63162306a36Sopenharmony_ci tipc_group_proto_xmit(grp, pm, GRP_ADV_MSG, xmitq); 63262306a36Sopenharmony_ci break; 63362306a36Sopenharmony_ci case MBR_ACTIVE: 63462306a36Sopenharmony_ci if (!list_is_last(&m->list, &grp->active)) 63562306a36Sopenharmony_ci list_move_tail(&m->list, &grp->active); 63662306a36Sopenharmony_ci if (m->advertised > (ADV_ACTIVE * 3 / 4)) 63762306a36Sopenharmony_ci break; 63862306a36Sopenharmony_ci tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq); 63962306a36Sopenharmony_ci break; 64062306a36Sopenharmony_ci case MBR_REMITTED: 64162306a36Sopenharmony_ci if (m->advertised > ADV_IDLE) 64262306a36Sopenharmony_ci break; 64362306a36Sopenharmony_ci m->state = MBR_JOINED; 64462306a36Sopenharmony_ci grp->active_cnt--; 64562306a36Sopenharmony_ci if (m->advertised < ADV_IDLE) { 64662306a36Sopenharmony_ci pr_warn_ratelimited("Rcv unexpected msg after REMIT\n"); 64762306a36Sopenharmony_ci tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq); 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (list_empty(&grp->pending)) 65162306a36Sopenharmony_ci return; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci /* Set oldest pending member to active and advertise */ 65462306a36Sopenharmony_ci pm = list_first_entry(&grp->pending, struct tipc_member, list); 65562306a36Sopenharmony_ci pm->state = MBR_ACTIVE; 65662306a36Sopenharmony_ci list_move_tail(&pm->list, &grp->active); 65762306a36Sopenharmony_ci grp->active_cnt++; 65862306a36Sopenharmony_ci tipc_group_proto_xmit(grp, pm, GRP_ADV_MSG, xmitq); 65962306a36Sopenharmony_ci break; 66062306a36Sopenharmony_ci case MBR_RECLAIMING: 66162306a36Sopenharmony_ci case MBR_JOINING: 66262306a36Sopenharmony_ci case MBR_LEAVING: 66362306a36Sopenharmony_ci default: 66462306a36Sopenharmony_ci break; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic void tipc_group_create_event(struct tipc_group *grp, 66962306a36Sopenharmony_ci struct tipc_member *m, 67062306a36Sopenharmony_ci u32 event, u16 seqno, 67162306a36Sopenharmony_ci struct sk_buff_head *inputq) 67262306a36Sopenharmony_ci{ u32 dnode = tipc_own_addr(grp->net); 67362306a36Sopenharmony_ci struct tipc_event evt; 67462306a36Sopenharmony_ci struct sk_buff *skb; 67562306a36Sopenharmony_ci struct tipc_msg *hdr; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci memset(&evt, 0, sizeof(evt)); 67862306a36Sopenharmony_ci evt.event = event; 67962306a36Sopenharmony_ci evt.found_lower = m->instance; 68062306a36Sopenharmony_ci evt.found_upper = m->instance; 68162306a36Sopenharmony_ci evt.port.ref = m->port; 68262306a36Sopenharmony_ci evt.port.node = m->node; 68362306a36Sopenharmony_ci evt.s.seq.type = grp->type; 68462306a36Sopenharmony_ci evt.s.seq.lower = m->instance; 68562306a36Sopenharmony_ci evt.s.seq.upper = m->instance; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_GRP_MEMBER_EVT, 68862306a36Sopenharmony_ci GROUP_H_SIZE, sizeof(evt), dnode, m->node, 68962306a36Sopenharmony_ci grp->portid, m->port, 0); 69062306a36Sopenharmony_ci if (!skb) 69162306a36Sopenharmony_ci return; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci hdr = buf_msg(skb); 69462306a36Sopenharmony_ci msg_set_nametype(hdr, grp->type); 69562306a36Sopenharmony_ci msg_set_grp_evt(hdr, event); 69662306a36Sopenharmony_ci msg_set_dest_droppable(hdr, true); 69762306a36Sopenharmony_ci msg_set_grp_bc_seqno(hdr, seqno); 69862306a36Sopenharmony_ci memcpy(msg_data(hdr), &evt, sizeof(evt)); 69962306a36Sopenharmony_ci TIPC_SKB_CB(skb)->orig_member = m->instance; 70062306a36Sopenharmony_ci __skb_queue_tail(inputq, skb); 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m, 70462306a36Sopenharmony_ci int mtyp, struct sk_buff_head *xmitq) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci struct tipc_msg *hdr; 70762306a36Sopenharmony_ci struct sk_buff *skb; 70862306a36Sopenharmony_ci int adv = 0; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci skb = tipc_msg_create(GROUP_PROTOCOL, mtyp, INT_H_SIZE, 0, 71162306a36Sopenharmony_ci m->node, tipc_own_addr(grp->net), 71262306a36Sopenharmony_ci m->port, grp->portid, 0); 71362306a36Sopenharmony_ci if (!skb) 71462306a36Sopenharmony_ci return; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci if (m->state == MBR_ACTIVE) 71762306a36Sopenharmony_ci adv = ADV_ACTIVE - m->advertised; 71862306a36Sopenharmony_ci else if (m->state == MBR_JOINED || m->state == MBR_PENDING) 71962306a36Sopenharmony_ci adv = ADV_IDLE - m->advertised; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci hdr = buf_msg(skb); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if (mtyp == GRP_JOIN_MSG) { 72462306a36Sopenharmony_ci msg_set_grp_bc_syncpt(hdr, grp->bc_snd_nxt); 72562306a36Sopenharmony_ci msg_set_adv_win(hdr, adv); 72662306a36Sopenharmony_ci m->advertised += adv; 72762306a36Sopenharmony_ci } else if (mtyp == GRP_LEAVE_MSG) { 72862306a36Sopenharmony_ci msg_set_grp_bc_syncpt(hdr, grp->bc_snd_nxt); 72962306a36Sopenharmony_ci } else if (mtyp == GRP_ADV_MSG) { 73062306a36Sopenharmony_ci msg_set_adv_win(hdr, adv); 73162306a36Sopenharmony_ci m->advertised += adv; 73262306a36Sopenharmony_ci } else if (mtyp == GRP_ACK_MSG) { 73362306a36Sopenharmony_ci msg_set_grp_bc_acked(hdr, m->bc_rcv_nxt); 73462306a36Sopenharmony_ci } else if (mtyp == GRP_REMIT_MSG) { 73562306a36Sopenharmony_ci msg_set_grp_remitted(hdr, m->window); 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci msg_set_dest_droppable(hdr, true); 73862306a36Sopenharmony_ci __skb_queue_tail(xmitq, skb); 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_civoid tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup, 74262306a36Sopenharmony_ci struct tipc_msg *hdr, struct sk_buff_head *inputq, 74362306a36Sopenharmony_ci struct sk_buff_head *xmitq) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci u32 node = msg_orignode(hdr); 74662306a36Sopenharmony_ci u32 port = msg_origport(hdr); 74762306a36Sopenharmony_ci struct tipc_member *m, *pm; 74862306a36Sopenharmony_ci u16 remitted, in_flight; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (!grp) 75162306a36Sopenharmony_ci return; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (grp->scope == TIPC_NODE_SCOPE && node != tipc_own_addr(grp->net)) 75462306a36Sopenharmony_ci return; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci m = tipc_group_find_member(grp, node, port); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci switch (msg_type(hdr)) { 75962306a36Sopenharmony_ci case GRP_JOIN_MSG: 76062306a36Sopenharmony_ci if (!m) 76162306a36Sopenharmony_ci m = tipc_group_create_member(grp, node, port, 76262306a36Sopenharmony_ci 0, MBR_JOINING); 76362306a36Sopenharmony_ci if (!m) 76462306a36Sopenharmony_ci return; 76562306a36Sopenharmony_ci m->bc_syncpt = msg_grp_bc_syncpt(hdr); 76662306a36Sopenharmony_ci m->bc_rcv_nxt = m->bc_syncpt; 76762306a36Sopenharmony_ci m->window += msg_adv_win(hdr); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* Wait until PUBLISH event is received if necessary */ 77062306a36Sopenharmony_ci if (m->state != MBR_PUBLISHED) 77162306a36Sopenharmony_ci return; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci /* Member can be taken into service */ 77462306a36Sopenharmony_ci m->state = MBR_JOINED; 77562306a36Sopenharmony_ci tipc_group_open(m, usr_wakeup); 77662306a36Sopenharmony_ci tipc_group_update_member(m, 0); 77762306a36Sopenharmony_ci tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq); 77862306a36Sopenharmony_ci tipc_group_create_event(grp, m, TIPC_PUBLISHED, 77962306a36Sopenharmony_ci m->bc_syncpt, inputq); 78062306a36Sopenharmony_ci return; 78162306a36Sopenharmony_ci case GRP_LEAVE_MSG: 78262306a36Sopenharmony_ci if (!m) 78362306a36Sopenharmony_ci return; 78462306a36Sopenharmony_ci m->bc_syncpt = msg_grp_bc_syncpt(hdr); 78562306a36Sopenharmony_ci list_del_init(&m->list); 78662306a36Sopenharmony_ci tipc_group_open(m, usr_wakeup); 78762306a36Sopenharmony_ci tipc_group_decr_active(grp, m); 78862306a36Sopenharmony_ci m->state = MBR_LEAVING; 78962306a36Sopenharmony_ci tipc_group_create_event(grp, m, TIPC_WITHDRAWN, 79062306a36Sopenharmony_ci m->bc_syncpt, inputq); 79162306a36Sopenharmony_ci return; 79262306a36Sopenharmony_ci case GRP_ADV_MSG: 79362306a36Sopenharmony_ci if (!m) 79462306a36Sopenharmony_ci return; 79562306a36Sopenharmony_ci m->window += msg_adv_win(hdr); 79662306a36Sopenharmony_ci tipc_group_open(m, usr_wakeup); 79762306a36Sopenharmony_ci return; 79862306a36Sopenharmony_ci case GRP_ACK_MSG: 79962306a36Sopenharmony_ci if (!m) 80062306a36Sopenharmony_ci return; 80162306a36Sopenharmony_ci m->bc_acked = msg_grp_bc_acked(hdr); 80262306a36Sopenharmony_ci if (--grp->bc_ackers) 80362306a36Sopenharmony_ci return; 80462306a36Sopenharmony_ci list_del_init(&m->small_win); 80562306a36Sopenharmony_ci *m->group->open = true; 80662306a36Sopenharmony_ci *usr_wakeup = true; 80762306a36Sopenharmony_ci tipc_group_update_member(m, 0); 80862306a36Sopenharmony_ci return; 80962306a36Sopenharmony_ci case GRP_RECLAIM_MSG: 81062306a36Sopenharmony_ci if (!m) 81162306a36Sopenharmony_ci return; 81262306a36Sopenharmony_ci tipc_group_proto_xmit(grp, m, GRP_REMIT_MSG, xmitq); 81362306a36Sopenharmony_ci m->window = ADV_IDLE; 81462306a36Sopenharmony_ci tipc_group_open(m, usr_wakeup); 81562306a36Sopenharmony_ci return; 81662306a36Sopenharmony_ci case GRP_REMIT_MSG: 81762306a36Sopenharmony_ci if (!m || m->state != MBR_RECLAIMING) 81862306a36Sopenharmony_ci return; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci remitted = msg_grp_remitted(hdr); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci /* Messages preceding the REMIT still in receive queue */ 82362306a36Sopenharmony_ci if (m->advertised > remitted) { 82462306a36Sopenharmony_ci m->state = MBR_REMITTED; 82562306a36Sopenharmony_ci in_flight = m->advertised - remitted; 82662306a36Sopenharmony_ci m->advertised = ADV_IDLE + in_flight; 82762306a36Sopenharmony_ci return; 82862306a36Sopenharmony_ci } 82962306a36Sopenharmony_ci /* This should never happen */ 83062306a36Sopenharmony_ci if (m->advertised < remitted) 83162306a36Sopenharmony_ci pr_warn_ratelimited("Unexpected REMIT msg\n"); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* All messages preceding the REMIT have been read */ 83462306a36Sopenharmony_ci m->state = MBR_JOINED; 83562306a36Sopenharmony_ci grp->active_cnt--; 83662306a36Sopenharmony_ci m->advertised = ADV_IDLE; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci /* Set oldest pending member to active and advertise */ 83962306a36Sopenharmony_ci if (list_empty(&grp->pending)) 84062306a36Sopenharmony_ci return; 84162306a36Sopenharmony_ci pm = list_first_entry(&grp->pending, struct tipc_member, list); 84262306a36Sopenharmony_ci pm->state = MBR_ACTIVE; 84362306a36Sopenharmony_ci list_move_tail(&pm->list, &grp->active); 84462306a36Sopenharmony_ci grp->active_cnt++; 84562306a36Sopenharmony_ci if (pm->advertised <= (ADV_ACTIVE * 3 / 4)) 84662306a36Sopenharmony_ci tipc_group_proto_xmit(grp, pm, GRP_ADV_MSG, xmitq); 84762306a36Sopenharmony_ci return; 84862306a36Sopenharmony_ci default: 84962306a36Sopenharmony_ci pr_warn("Received unknown GROUP_PROTO message\n"); 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci/* tipc_group_member_evt() - receive and handle a member up/down event 85462306a36Sopenharmony_ci */ 85562306a36Sopenharmony_civoid tipc_group_member_evt(struct tipc_group *grp, 85662306a36Sopenharmony_ci bool *usr_wakeup, 85762306a36Sopenharmony_ci int *sk_rcvbuf, 85862306a36Sopenharmony_ci struct tipc_msg *hdr, 85962306a36Sopenharmony_ci struct sk_buff_head *inputq, 86062306a36Sopenharmony_ci struct sk_buff_head *xmitq) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci struct tipc_event *evt = (void *)msg_data(hdr); 86362306a36Sopenharmony_ci u32 instance = evt->found_lower; 86462306a36Sopenharmony_ci u32 node = evt->port.node; 86562306a36Sopenharmony_ci u32 port = evt->port.ref; 86662306a36Sopenharmony_ci int event = evt->event; 86762306a36Sopenharmony_ci struct tipc_member *m; 86862306a36Sopenharmony_ci struct net *net; 86962306a36Sopenharmony_ci u32 self; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci if (!grp) 87262306a36Sopenharmony_ci return; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci net = grp->net; 87562306a36Sopenharmony_ci self = tipc_own_addr(net); 87662306a36Sopenharmony_ci if (!grp->loopback && node == self && port == grp->portid) 87762306a36Sopenharmony_ci return; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci m = tipc_group_find_member(grp, node, port); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci switch (event) { 88262306a36Sopenharmony_ci case TIPC_PUBLISHED: 88362306a36Sopenharmony_ci /* Send and wait for arrival of JOIN message if necessary */ 88462306a36Sopenharmony_ci if (!m) { 88562306a36Sopenharmony_ci m = tipc_group_create_member(grp, node, port, instance, 88662306a36Sopenharmony_ci MBR_PUBLISHED); 88762306a36Sopenharmony_ci if (!m) 88862306a36Sopenharmony_ci break; 88962306a36Sopenharmony_ci tipc_group_update_member(m, 0); 89062306a36Sopenharmony_ci tipc_group_proto_xmit(grp, m, GRP_JOIN_MSG, xmitq); 89162306a36Sopenharmony_ci break; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci if (m->state != MBR_JOINING) 89562306a36Sopenharmony_ci break; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci /* Member can be taken into service */ 89862306a36Sopenharmony_ci m->instance = instance; 89962306a36Sopenharmony_ci m->state = MBR_JOINED; 90062306a36Sopenharmony_ci tipc_group_open(m, usr_wakeup); 90162306a36Sopenharmony_ci tipc_group_update_member(m, 0); 90262306a36Sopenharmony_ci tipc_group_proto_xmit(grp, m, GRP_JOIN_MSG, xmitq); 90362306a36Sopenharmony_ci tipc_group_create_event(grp, m, TIPC_PUBLISHED, 90462306a36Sopenharmony_ci m->bc_syncpt, inputq); 90562306a36Sopenharmony_ci break; 90662306a36Sopenharmony_ci case TIPC_WITHDRAWN: 90762306a36Sopenharmony_ci if (!m) 90862306a36Sopenharmony_ci break; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci tipc_group_decr_active(grp, m); 91162306a36Sopenharmony_ci m->state = MBR_LEAVING; 91262306a36Sopenharmony_ci list_del_init(&m->list); 91362306a36Sopenharmony_ci tipc_group_open(m, usr_wakeup); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci /* Only send event if no LEAVE message can be expected */ 91662306a36Sopenharmony_ci if (!tipc_node_is_up(net, node)) 91762306a36Sopenharmony_ci tipc_group_create_event(grp, m, TIPC_WITHDRAWN, 91862306a36Sopenharmony_ci m->bc_rcv_nxt, inputq); 91962306a36Sopenharmony_ci break; 92062306a36Sopenharmony_ci default: 92162306a36Sopenharmony_ci break; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci *sk_rcvbuf = tipc_group_rcvbuf_limit(grp); 92462306a36Sopenharmony_ci} 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ciint tipc_group_fill_sock_diag(struct tipc_group *grp, struct sk_buff *skb) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci struct nlattr *group = nla_nest_start_noflag(skb, TIPC_NLA_SOCK_GROUP); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (!group) 93162306a36Sopenharmony_ci return -EMSGSIZE; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (nla_put_u32(skb, TIPC_NLA_SOCK_GROUP_ID, 93462306a36Sopenharmony_ci grp->type) || 93562306a36Sopenharmony_ci nla_put_u32(skb, TIPC_NLA_SOCK_GROUP_INSTANCE, 93662306a36Sopenharmony_ci grp->instance) || 93762306a36Sopenharmony_ci nla_put_u32(skb, TIPC_NLA_SOCK_GROUP_BC_SEND_NEXT, 93862306a36Sopenharmony_ci grp->bc_snd_nxt)) 93962306a36Sopenharmony_ci goto group_msg_cancel; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci if (grp->scope == TIPC_NODE_SCOPE) 94262306a36Sopenharmony_ci if (nla_put_flag(skb, TIPC_NLA_SOCK_GROUP_NODE_SCOPE)) 94362306a36Sopenharmony_ci goto group_msg_cancel; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (grp->scope == TIPC_CLUSTER_SCOPE) 94662306a36Sopenharmony_ci if (nla_put_flag(skb, TIPC_NLA_SOCK_GROUP_CLUSTER_SCOPE)) 94762306a36Sopenharmony_ci goto group_msg_cancel; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci if (*grp->open) 95062306a36Sopenharmony_ci if (nla_put_flag(skb, TIPC_NLA_SOCK_GROUP_OPEN)) 95162306a36Sopenharmony_ci goto group_msg_cancel; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci nla_nest_end(skb, group); 95462306a36Sopenharmony_ci return 0; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_cigroup_msg_cancel: 95762306a36Sopenharmony_ci nla_nest_cancel(skb, group); 95862306a36Sopenharmony_ci return -1; 95962306a36Sopenharmony_ci} 960