18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * net/tipc/group.c: TIPC group messaging code
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (c) 2017, Ericsson AB
58c2ecf20Sopenharmony_ci * All rights reserved.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
88c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
118c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
128c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
138c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
148c2ecf20Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
158c2ecf20Sopenharmony_ci * 3. Neither the names of the copyright holders nor the names of its
168c2ecf20Sopenharmony_ci *    contributors may be used to endorse or promote products derived from
178c2ecf20Sopenharmony_ci *    this software without specific prior written permission.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the
208c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free
218c2ecf20Sopenharmony_ci * Software Foundation.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
248c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
258c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
268c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
278c2ecf20Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
288c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
298c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
308c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
318c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
328c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
338c2ecf20Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE.
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#include "core.h"
378c2ecf20Sopenharmony_ci#include "addr.h"
388c2ecf20Sopenharmony_ci#include "group.h"
398c2ecf20Sopenharmony_ci#include "bcast.h"
408c2ecf20Sopenharmony_ci#include "topsrv.h"
418c2ecf20Sopenharmony_ci#include "msg.h"
428c2ecf20Sopenharmony_ci#include "socket.h"
438c2ecf20Sopenharmony_ci#include "node.h"
448c2ecf20Sopenharmony_ci#include "name_table.h"
458c2ecf20Sopenharmony_ci#include "subscr.h"
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define ADV_UNIT (((MAX_MSG_SIZE + MAX_H_SIZE) / FLOWCTL_BLK_SZ) + 1)
488c2ecf20Sopenharmony_ci#define ADV_IDLE ADV_UNIT
498c2ecf20Sopenharmony_ci#define ADV_ACTIVE (ADV_UNIT * 12)
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cienum mbr_state {
528c2ecf20Sopenharmony_ci	MBR_JOINING,
538c2ecf20Sopenharmony_ci	MBR_PUBLISHED,
548c2ecf20Sopenharmony_ci	MBR_JOINED,
558c2ecf20Sopenharmony_ci	MBR_PENDING,
568c2ecf20Sopenharmony_ci	MBR_ACTIVE,
578c2ecf20Sopenharmony_ci	MBR_RECLAIMING,
588c2ecf20Sopenharmony_ci	MBR_REMITTED,
598c2ecf20Sopenharmony_ci	MBR_LEAVING
608c2ecf20Sopenharmony_ci};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistruct tipc_member {
638c2ecf20Sopenharmony_ci	struct rb_node tree_node;
648c2ecf20Sopenharmony_ci	struct list_head list;
658c2ecf20Sopenharmony_ci	struct list_head small_win;
668c2ecf20Sopenharmony_ci	struct sk_buff_head deferredq;
678c2ecf20Sopenharmony_ci	struct tipc_group *group;
688c2ecf20Sopenharmony_ci	u32 node;
698c2ecf20Sopenharmony_ci	u32 port;
708c2ecf20Sopenharmony_ci	u32 instance;
718c2ecf20Sopenharmony_ci	enum mbr_state state;
728c2ecf20Sopenharmony_ci	u16 advertised;
738c2ecf20Sopenharmony_ci	u16 window;
748c2ecf20Sopenharmony_ci	u16 bc_rcv_nxt;
758c2ecf20Sopenharmony_ci	u16 bc_syncpt;
768c2ecf20Sopenharmony_ci	u16 bc_acked;
778c2ecf20Sopenharmony_ci};
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistruct tipc_group {
808c2ecf20Sopenharmony_ci	struct rb_root members;
818c2ecf20Sopenharmony_ci	struct list_head small_win;
828c2ecf20Sopenharmony_ci	struct list_head pending;
838c2ecf20Sopenharmony_ci	struct list_head active;
848c2ecf20Sopenharmony_ci	struct tipc_nlist dests;
858c2ecf20Sopenharmony_ci	struct net *net;
868c2ecf20Sopenharmony_ci	int subid;
878c2ecf20Sopenharmony_ci	u32 type;
888c2ecf20Sopenharmony_ci	u32 instance;
898c2ecf20Sopenharmony_ci	u32 scope;
908c2ecf20Sopenharmony_ci	u32 portid;
918c2ecf20Sopenharmony_ci	u16 member_cnt;
928c2ecf20Sopenharmony_ci	u16 active_cnt;
938c2ecf20Sopenharmony_ci	u16 max_active;
948c2ecf20Sopenharmony_ci	u16 bc_snd_nxt;
958c2ecf20Sopenharmony_ci	u16 bc_ackers;
968c2ecf20Sopenharmony_ci	bool *open;
978c2ecf20Sopenharmony_ci	bool loopback;
988c2ecf20Sopenharmony_ci	bool events;
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m,
1028c2ecf20Sopenharmony_ci				  int mtyp, struct sk_buff_head *xmitq);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic void tipc_group_open(struct tipc_member *m, bool *wakeup)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	*wakeup = false;
1078c2ecf20Sopenharmony_ci	if (list_empty(&m->small_win))
1088c2ecf20Sopenharmony_ci		return;
1098c2ecf20Sopenharmony_ci	list_del_init(&m->small_win);
1108c2ecf20Sopenharmony_ci	*m->group->open = true;
1118c2ecf20Sopenharmony_ci	*wakeup = true;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic void tipc_group_decr_active(struct tipc_group *grp,
1158c2ecf20Sopenharmony_ci				   struct tipc_member *m)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	if (m->state == MBR_ACTIVE || m->state == MBR_RECLAIMING ||
1188c2ecf20Sopenharmony_ci	    m->state == MBR_REMITTED)
1198c2ecf20Sopenharmony_ci		grp->active_cnt--;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic int tipc_group_rcvbuf_limit(struct tipc_group *grp)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	int max_active, active_pool, idle_pool;
1258c2ecf20Sopenharmony_ci	int mcnt = grp->member_cnt + 1;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	/* Limit simultaneous reception from other members */
1288c2ecf20Sopenharmony_ci	max_active = min(mcnt / 8, 64);
1298c2ecf20Sopenharmony_ci	max_active = max(max_active, 16);
1308c2ecf20Sopenharmony_ci	grp->max_active = max_active;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	/* Reserve blocks for active and idle members */
1338c2ecf20Sopenharmony_ci	active_pool = max_active * ADV_ACTIVE;
1348c2ecf20Sopenharmony_ci	idle_pool = (mcnt - max_active) * ADV_IDLE;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	/* Scale to bytes, considering worst-case truesize/msgsize ratio */
1378c2ecf20Sopenharmony_ci	return (active_pool + idle_pool) * FLOWCTL_BLK_SZ * 4;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ciu16 tipc_group_bc_snd_nxt(struct tipc_group *grp)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	return grp->bc_snd_nxt;
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic bool tipc_group_is_receiver(struct tipc_member *m)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	return m && m->state != MBR_JOINING && m->state != MBR_LEAVING;
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic bool tipc_group_is_sender(struct tipc_member *m)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	return m && m->state != MBR_JOINING && m->state != MBR_PUBLISHED;
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ciu32 tipc_group_exclude(struct tipc_group *grp)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	if (!grp->loopback)
1588c2ecf20Sopenharmony_ci		return grp->portid;
1598c2ecf20Sopenharmony_ci	return 0;
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistruct tipc_group *tipc_group_create(struct net *net, u32 portid,
1638c2ecf20Sopenharmony_ci				     struct tipc_group_req *mreq,
1648c2ecf20Sopenharmony_ci				     bool *group_is_open)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	u32 filter = TIPC_SUB_PORTS | TIPC_SUB_NO_STATUS;
1678c2ecf20Sopenharmony_ci	bool global = mreq->scope != TIPC_NODE_SCOPE;
1688c2ecf20Sopenharmony_ci	struct tipc_group *grp;
1698c2ecf20Sopenharmony_ci	u32 type = mreq->type;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	grp = kzalloc(sizeof(*grp), GFP_ATOMIC);
1728c2ecf20Sopenharmony_ci	if (!grp)
1738c2ecf20Sopenharmony_ci		return NULL;
1748c2ecf20Sopenharmony_ci	tipc_nlist_init(&grp->dests, tipc_own_addr(net));
1758c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&grp->small_win);
1768c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&grp->active);
1778c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&grp->pending);
1788c2ecf20Sopenharmony_ci	grp->members = RB_ROOT;
1798c2ecf20Sopenharmony_ci	grp->net = net;
1808c2ecf20Sopenharmony_ci	grp->portid = portid;
1818c2ecf20Sopenharmony_ci	grp->type = type;
1828c2ecf20Sopenharmony_ci	grp->instance = mreq->instance;
1838c2ecf20Sopenharmony_ci	grp->scope = mreq->scope;
1848c2ecf20Sopenharmony_ci	grp->loopback = mreq->flags & TIPC_GROUP_LOOPBACK;
1858c2ecf20Sopenharmony_ci	grp->events = mreq->flags & TIPC_GROUP_MEMBER_EVTS;
1868c2ecf20Sopenharmony_ci	grp->open = group_is_open;
1878c2ecf20Sopenharmony_ci	*grp->open = false;
1888c2ecf20Sopenharmony_ci	filter |= global ? TIPC_SUB_CLUSTER_SCOPE : TIPC_SUB_NODE_SCOPE;
1898c2ecf20Sopenharmony_ci	if (tipc_topsrv_kern_subscr(net, portid, type, 0, ~0,
1908c2ecf20Sopenharmony_ci				    filter, &grp->subid))
1918c2ecf20Sopenharmony_ci		return grp;
1928c2ecf20Sopenharmony_ci	kfree(grp);
1938c2ecf20Sopenharmony_ci	return NULL;
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_civoid tipc_group_join(struct net *net, struct tipc_group *grp, int *sk_rcvbuf)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	struct rb_root *tree = &grp->members;
1998c2ecf20Sopenharmony_ci	struct tipc_member *m, *tmp;
2008c2ecf20Sopenharmony_ci	struct sk_buff_head xmitq;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	__skb_queue_head_init(&xmitq);
2038c2ecf20Sopenharmony_ci	rbtree_postorder_for_each_entry_safe(m, tmp, tree, tree_node) {
2048c2ecf20Sopenharmony_ci		tipc_group_proto_xmit(grp, m, GRP_JOIN_MSG, &xmitq);
2058c2ecf20Sopenharmony_ci		tipc_group_update_member(m, 0);
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci	tipc_node_distr_xmit(net, &xmitq);
2088c2ecf20Sopenharmony_ci	*sk_rcvbuf = tipc_group_rcvbuf_limit(grp);
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_civoid tipc_group_delete(struct net *net, struct tipc_group *grp)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct rb_root *tree = &grp->members;
2148c2ecf20Sopenharmony_ci	struct tipc_member *m, *tmp;
2158c2ecf20Sopenharmony_ci	struct sk_buff_head xmitq;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	__skb_queue_head_init(&xmitq);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	rbtree_postorder_for_each_entry_safe(m, tmp, tree, tree_node) {
2208c2ecf20Sopenharmony_ci		tipc_group_proto_xmit(grp, m, GRP_LEAVE_MSG, &xmitq);
2218c2ecf20Sopenharmony_ci		__skb_queue_purge(&m->deferredq);
2228c2ecf20Sopenharmony_ci		list_del(&m->list);
2238c2ecf20Sopenharmony_ci		kfree(m);
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci	tipc_node_distr_xmit(net, &xmitq);
2268c2ecf20Sopenharmony_ci	tipc_nlist_purge(&grp->dests);
2278c2ecf20Sopenharmony_ci	tipc_topsrv_kern_unsubscr(net, grp->subid);
2288c2ecf20Sopenharmony_ci	kfree(grp);
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic struct tipc_member *tipc_group_find_member(struct tipc_group *grp,
2328c2ecf20Sopenharmony_ci						  u32 node, u32 port)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	struct rb_node *n = grp->members.rb_node;
2358c2ecf20Sopenharmony_ci	u64 nkey, key = (u64)node << 32 | port;
2368c2ecf20Sopenharmony_ci	struct tipc_member *m;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	while (n) {
2398c2ecf20Sopenharmony_ci		m = container_of(n, struct tipc_member, tree_node);
2408c2ecf20Sopenharmony_ci		nkey = (u64)m->node << 32 | m->port;
2418c2ecf20Sopenharmony_ci		if (key < nkey)
2428c2ecf20Sopenharmony_ci			n = n->rb_left;
2438c2ecf20Sopenharmony_ci		else if (key > nkey)
2448c2ecf20Sopenharmony_ci			n = n->rb_right;
2458c2ecf20Sopenharmony_ci		else
2468c2ecf20Sopenharmony_ci			return m;
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci	return NULL;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic struct tipc_member *tipc_group_find_dest(struct tipc_group *grp,
2528c2ecf20Sopenharmony_ci						u32 node, u32 port)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	struct tipc_member *m;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	m = tipc_group_find_member(grp, node, port);
2578c2ecf20Sopenharmony_ci	if (m && tipc_group_is_receiver(m))
2588c2ecf20Sopenharmony_ci		return m;
2598c2ecf20Sopenharmony_ci	return NULL;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_cistatic struct tipc_member *tipc_group_find_node(struct tipc_group *grp,
2638c2ecf20Sopenharmony_ci						u32 node)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	struct tipc_member *m;
2668c2ecf20Sopenharmony_ci	struct rb_node *n;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	for (n = rb_first(&grp->members); n; n = rb_next(n)) {
2698c2ecf20Sopenharmony_ci		m = container_of(n, struct tipc_member, tree_node);
2708c2ecf20Sopenharmony_ci		if (m->node == node)
2718c2ecf20Sopenharmony_ci			return m;
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci	return NULL;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic int tipc_group_add_to_tree(struct tipc_group *grp,
2778c2ecf20Sopenharmony_ci				  struct tipc_member *m)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	u64 nkey, key = (u64)m->node << 32 | m->port;
2808c2ecf20Sopenharmony_ci	struct rb_node **n, *parent = NULL;
2818c2ecf20Sopenharmony_ci	struct tipc_member *tmp;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	n = &grp->members.rb_node;
2848c2ecf20Sopenharmony_ci	while (*n) {
2858c2ecf20Sopenharmony_ci		tmp = container_of(*n, struct tipc_member, tree_node);
2868c2ecf20Sopenharmony_ci		parent = *n;
2878c2ecf20Sopenharmony_ci		tmp = container_of(parent, struct tipc_member, tree_node);
2888c2ecf20Sopenharmony_ci		nkey = (u64)tmp->node << 32 | tmp->port;
2898c2ecf20Sopenharmony_ci		if (key < nkey)
2908c2ecf20Sopenharmony_ci			n = &(*n)->rb_left;
2918c2ecf20Sopenharmony_ci		else if (key > nkey)
2928c2ecf20Sopenharmony_ci			n = &(*n)->rb_right;
2938c2ecf20Sopenharmony_ci		else
2948c2ecf20Sopenharmony_ci			return -EEXIST;
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci	rb_link_node(&m->tree_node, parent, n);
2978c2ecf20Sopenharmony_ci	rb_insert_color(&m->tree_node, &grp->members);
2988c2ecf20Sopenharmony_ci	return 0;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic struct tipc_member *tipc_group_create_member(struct tipc_group *grp,
3028c2ecf20Sopenharmony_ci						    u32 node, u32 port,
3038c2ecf20Sopenharmony_ci						    u32 instance, int state)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	struct tipc_member *m;
3068c2ecf20Sopenharmony_ci	int ret;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	m = kzalloc(sizeof(*m), GFP_ATOMIC);
3098c2ecf20Sopenharmony_ci	if (!m)
3108c2ecf20Sopenharmony_ci		return NULL;
3118c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&m->list);
3128c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&m->small_win);
3138c2ecf20Sopenharmony_ci	__skb_queue_head_init(&m->deferredq);
3148c2ecf20Sopenharmony_ci	m->group = grp;
3158c2ecf20Sopenharmony_ci	m->node = node;
3168c2ecf20Sopenharmony_ci	m->port = port;
3178c2ecf20Sopenharmony_ci	m->instance = instance;
3188c2ecf20Sopenharmony_ci	m->bc_acked = grp->bc_snd_nxt - 1;
3198c2ecf20Sopenharmony_ci	ret = tipc_group_add_to_tree(grp, m);
3208c2ecf20Sopenharmony_ci	if (ret < 0) {
3218c2ecf20Sopenharmony_ci		kfree(m);
3228c2ecf20Sopenharmony_ci		return NULL;
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci	grp->member_cnt++;
3258c2ecf20Sopenharmony_ci	tipc_nlist_add(&grp->dests, m->node);
3268c2ecf20Sopenharmony_ci	m->state = state;
3278c2ecf20Sopenharmony_ci	return m;
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_civoid tipc_group_add_member(struct tipc_group *grp, u32 node,
3318c2ecf20Sopenharmony_ci			   u32 port, u32 instance)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	tipc_group_create_member(grp, node, port, instance, MBR_PUBLISHED);
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic void tipc_group_delete_member(struct tipc_group *grp,
3378c2ecf20Sopenharmony_ci				     struct tipc_member *m)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	rb_erase(&m->tree_node, &grp->members);
3408c2ecf20Sopenharmony_ci	grp->member_cnt--;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	/* Check if we were waiting for replicast ack from this member */
3438c2ecf20Sopenharmony_ci	if (grp->bc_ackers && less(m->bc_acked, grp->bc_snd_nxt - 1))
3448c2ecf20Sopenharmony_ci		grp->bc_ackers--;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	list_del_init(&m->list);
3478c2ecf20Sopenharmony_ci	list_del_init(&m->small_win);
3488c2ecf20Sopenharmony_ci	tipc_group_decr_active(grp, m);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	/* If last member on a node, remove node from dest list */
3518c2ecf20Sopenharmony_ci	if (!tipc_group_find_node(grp, m->node))
3528c2ecf20Sopenharmony_ci		tipc_nlist_del(&grp->dests, m->node);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	kfree(m);
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistruct tipc_nlist *tipc_group_dests(struct tipc_group *grp)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	return &grp->dests;
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_civoid tipc_group_self(struct tipc_group *grp, struct tipc_name_seq *seq,
3638c2ecf20Sopenharmony_ci		     int *scope)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	seq->type = grp->type;
3668c2ecf20Sopenharmony_ci	seq->lower = grp->instance;
3678c2ecf20Sopenharmony_ci	seq->upper = grp->instance;
3688c2ecf20Sopenharmony_ci	*scope = grp->scope;
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_civoid tipc_group_update_member(struct tipc_member *m, int len)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct tipc_group *grp = m->group;
3748c2ecf20Sopenharmony_ci	struct tipc_member *_m, *tmp;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	if (!tipc_group_is_receiver(m))
3778c2ecf20Sopenharmony_ci		return;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	m->window -= len;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	if (m->window >= ADV_IDLE)
3828c2ecf20Sopenharmony_ci		return;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	list_del_init(&m->small_win);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	/* Sort member into small_window members' list */
3878c2ecf20Sopenharmony_ci	list_for_each_entry_safe(_m, tmp, &grp->small_win, small_win) {
3888c2ecf20Sopenharmony_ci		if (_m->window > m->window)
3898c2ecf20Sopenharmony_ci			break;
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci	list_add_tail(&m->small_win, &_m->small_win);
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_civoid tipc_group_update_bc_members(struct tipc_group *grp, int len, bool ack)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	u16 prev = grp->bc_snd_nxt - 1;
3978c2ecf20Sopenharmony_ci	struct tipc_member *m;
3988c2ecf20Sopenharmony_ci	struct rb_node *n;
3998c2ecf20Sopenharmony_ci	u16 ackers = 0;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	for (n = rb_first(&grp->members); n; n = rb_next(n)) {
4028c2ecf20Sopenharmony_ci		m = container_of(n, struct tipc_member, tree_node);
4038c2ecf20Sopenharmony_ci		if (tipc_group_is_receiver(m)) {
4048c2ecf20Sopenharmony_ci			tipc_group_update_member(m, len);
4058c2ecf20Sopenharmony_ci			m->bc_acked = prev;
4068c2ecf20Sopenharmony_ci			ackers++;
4078c2ecf20Sopenharmony_ci		}
4088c2ecf20Sopenharmony_ci	}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	/* Mark number of acknowledges to expect, if any */
4118c2ecf20Sopenharmony_ci	if (ack)
4128c2ecf20Sopenharmony_ci		grp->bc_ackers = ackers;
4138c2ecf20Sopenharmony_ci	grp->bc_snd_nxt++;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cibool tipc_group_cong(struct tipc_group *grp, u32 dnode, u32 dport,
4178c2ecf20Sopenharmony_ci		     int len, struct tipc_member **mbr)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	struct sk_buff_head xmitq;
4208c2ecf20Sopenharmony_ci	struct tipc_member *m;
4218c2ecf20Sopenharmony_ci	int adv, state;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	m = tipc_group_find_dest(grp, dnode, dport);
4248c2ecf20Sopenharmony_ci	if (!tipc_group_is_receiver(m)) {
4258c2ecf20Sopenharmony_ci		*mbr = NULL;
4268c2ecf20Sopenharmony_ci		return false;
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci	*mbr = m;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	if (m->window >= len)
4318c2ecf20Sopenharmony_ci		return false;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	*grp->open = false;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	/* If not fully advertised, do it now to prevent mutual blocking */
4368c2ecf20Sopenharmony_ci	adv = m->advertised;
4378c2ecf20Sopenharmony_ci	state = m->state;
4388c2ecf20Sopenharmony_ci	if (state == MBR_JOINED && adv == ADV_IDLE)
4398c2ecf20Sopenharmony_ci		return true;
4408c2ecf20Sopenharmony_ci	if (state == MBR_ACTIVE && adv == ADV_ACTIVE)
4418c2ecf20Sopenharmony_ci		return true;
4428c2ecf20Sopenharmony_ci	if (state == MBR_PENDING && adv == ADV_IDLE)
4438c2ecf20Sopenharmony_ci		return true;
4448c2ecf20Sopenharmony_ci	__skb_queue_head_init(&xmitq);
4458c2ecf20Sopenharmony_ci	tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, &xmitq);
4468c2ecf20Sopenharmony_ci	tipc_node_distr_xmit(grp->net, &xmitq);
4478c2ecf20Sopenharmony_ci	return true;
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cibool tipc_group_bc_cong(struct tipc_group *grp, int len)
4518c2ecf20Sopenharmony_ci{
4528c2ecf20Sopenharmony_ci	struct tipc_member *m = NULL;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	/* If prev bcast was replicast, reject until all receivers have acked */
4558c2ecf20Sopenharmony_ci	if (grp->bc_ackers) {
4568c2ecf20Sopenharmony_ci		*grp->open = false;
4578c2ecf20Sopenharmony_ci		return true;
4588c2ecf20Sopenharmony_ci	}
4598c2ecf20Sopenharmony_ci	if (list_empty(&grp->small_win))
4608c2ecf20Sopenharmony_ci		return false;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	m = list_first_entry(&grp->small_win, struct tipc_member, small_win);
4638c2ecf20Sopenharmony_ci	if (m->window >= len)
4648c2ecf20Sopenharmony_ci		return false;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	return tipc_group_cong(grp, m->node, m->port, len, &m);
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci/* tipc_group_sort_msg() - sort msg into queue by bcast sequence number
4708c2ecf20Sopenharmony_ci */
4718c2ecf20Sopenharmony_cistatic void tipc_group_sort_msg(struct sk_buff *skb, struct sk_buff_head *defq)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	struct tipc_msg *_hdr, *hdr = buf_msg(skb);
4748c2ecf20Sopenharmony_ci	u16 bc_seqno = msg_grp_bc_seqno(hdr);
4758c2ecf20Sopenharmony_ci	struct sk_buff *_skb, *tmp;
4768c2ecf20Sopenharmony_ci	int mtyp = msg_type(hdr);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	/* Bcast/mcast may be bypassed by ucast or other bcast, - sort it in */
4798c2ecf20Sopenharmony_ci	if (mtyp == TIPC_GRP_BCAST_MSG || mtyp == TIPC_GRP_MCAST_MSG) {
4808c2ecf20Sopenharmony_ci		skb_queue_walk_safe(defq, _skb, tmp) {
4818c2ecf20Sopenharmony_ci			_hdr = buf_msg(_skb);
4828c2ecf20Sopenharmony_ci			if (!less(bc_seqno, msg_grp_bc_seqno(_hdr)))
4838c2ecf20Sopenharmony_ci				continue;
4848c2ecf20Sopenharmony_ci			__skb_queue_before(defq, _skb, skb);
4858c2ecf20Sopenharmony_ci			return;
4868c2ecf20Sopenharmony_ci		}
4878c2ecf20Sopenharmony_ci		/* Bcast was not bypassed, - add to tail */
4888c2ecf20Sopenharmony_ci	}
4898c2ecf20Sopenharmony_ci	/* Unicasts are never bypassed, - always add to tail */
4908c2ecf20Sopenharmony_ci	__skb_queue_tail(defq, skb);
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci/* tipc_group_filter_msg() - determine if we should accept arriving message
4948c2ecf20Sopenharmony_ci */
4958c2ecf20Sopenharmony_civoid tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
4968c2ecf20Sopenharmony_ci			   struct sk_buff_head *xmitq)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	struct sk_buff *skb = __skb_dequeue(inputq);
4998c2ecf20Sopenharmony_ci	bool ack, deliver, update, leave = false;
5008c2ecf20Sopenharmony_ci	struct sk_buff_head *defq;
5018c2ecf20Sopenharmony_ci	struct tipc_member *m;
5028c2ecf20Sopenharmony_ci	struct tipc_msg *hdr;
5038c2ecf20Sopenharmony_ci	u32 node, port;
5048c2ecf20Sopenharmony_ci	int mtyp, blks;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	if (!skb)
5078c2ecf20Sopenharmony_ci		return;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	hdr = buf_msg(skb);
5108c2ecf20Sopenharmony_ci	node =  msg_orignode(hdr);
5118c2ecf20Sopenharmony_ci	port = msg_origport(hdr);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	if (!msg_in_group(hdr))
5148c2ecf20Sopenharmony_ci		goto drop;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	m = tipc_group_find_member(grp, node, port);
5178c2ecf20Sopenharmony_ci	if (!tipc_group_is_sender(m))
5188c2ecf20Sopenharmony_ci		goto drop;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	if (less(msg_grp_bc_seqno(hdr), m->bc_rcv_nxt))
5218c2ecf20Sopenharmony_ci		goto drop;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	TIPC_SKB_CB(skb)->orig_member = m->instance;
5248c2ecf20Sopenharmony_ci	defq = &m->deferredq;
5258c2ecf20Sopenharmony_ci	tipc_group_sort_msg(skb, defq);
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	while ((skb = skb_peek(defq))) {
5288c2ecf20Sopenharmony_ci		hdr = buf_msg(skb);
5298c2ecf20Sopenharmony_ci		mtyp = msg_type(hdr);
5308c2ecf20Sopenharmony_ci		blks = msg_blocks(hdr);
5318c2ecf20Sopenharmony_ci		deliver = true;
5328c2ecf20Sopenharmony_ci		ack = false;
5338c2ecf20Sopenharmony_ci		update = false;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci		if (more(msg_grp_bc_seqno(hdr), m->bc_rcv_nxt))
5368c2ecf20Sopenharmony_ci			break;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci		/* Decide what to do with message */
5398c2ecf20Sopenharmony_ci		switch (mtyp) {
5408c2ecf20Sopenharmony_ci		case TIPC_GRP_MCAST_MSG:
5418c2ecf20Sopenharmony_ci			if (msg_nameinst(hdr) != grp->instance) {
5428c2ecf20Sopenharmony_ci				update = true;
5438c2ecf20Sopenharmony_ci				deliver = false;
5448c2ecf20Sopenharmony_ci			}
5458c2ecf20Sopenharmony_ci			fallthrough;
5468c2ecf20Sopenharmony_ci		case TIPC_GRP_BCAST_MSG:
5478c2ecf20Sopenharmony_ci			m->bc_rcv_nxt++;
5488c2ecf20Sopenharmony_ci			ack = msg_grp_bc_ack_req(hdr);
5498c2ecf20Sopenharmony_ci			break;
5508c2ecf20Sopenharmony_ci		case TIPC_GRP_UCAST_MSG:
5518c2ecf20Sopenharmony_ci			break;
5528c2ecf20Sopenharmony_ci		case TIPC_GRP_MEMBER_EVT:
5538c2ecf20Sopenharmony_ci			if (m->state == MBR_LEAVING)
5548c2ecf20Sopenharmony_ci				leave = true;
5558c2ecf20Sopenharmony_ci			if (!grp->events)
5568c2ecf20Sopenharmony_ci				deliver = false;
5578c2ecf20Sopenharmony_ci			break;
5588c2ecf20Sopenharmony_ci		default:
5598c2ecf20Sopenharmony_ci			break;
5608c2ecf20Sopenharmony_ci		}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci		/* Execute decisions */
5638c2ecf20Sopenharmony_ci		__skb_dequeue(defq);
5648c2ecf20Sopenharmony_ci		if (deliver)
5658c2ecf20Sopenharmony_ci			__skb_queue_tail(inputq, skb);
5668c2ecf20Sopenharmony_ci		else
5678c2ecf20Sopenharmony_ci			kfree_skb(skb);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci		if (ack)
5708c2ecf20Sopenharmony_ci			tipc_group_proto_xmit(grp, m, GRP_ACK_MSG, xmitq);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci		if (leave) {
5738c2ecf20Sopenharmony_ci			__skb_queue_purge(defq);
5748c2ecf20Sopenharmony_ci			tipc_group_delete_member(grp, m);
5758c2ecf20Sopenharmony_ci			break;
5768c2ecf20Sopenharmony_ci		}
5778c2ecf20Sopenharmony_ci		if (!update)
5788c2ecf20Sopenharmony_ci			continue;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci		tipc_group_update_rcv_win(grp, blks, node, port, xmitq);
5818c2ecf20Sopenharmony_ci	}
5828c2ecf20Sopenharmony_ci	return;
5838c2ecf20Sopenharmony_cidrop:
5848c2ecf20Sopenharmony_ci	kfree_skb(skb);
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_civoid tipc_group_update_rcv_win(struct tipc_group *grp, int blks, u32 node,
5888c2ecf20Sopenharmony_ci			       u32 port, struct sk_buff_head *xmitq)
5898c2ecf20Sopenharmony_ci{
5908c2ecf20Sopenharmony_ci	struct list_head *active = &grp->active;
5918c2ecf20Sopenharmony_ci	int max_active = grp->max_active;
5928c2ecf20Sopenharmony_ci	int reclaim_limit = max_active * 3 / 4;
5938c2ecf20Sopenharmony_ci	int active_cnt = grp->active_cnt;
5948c2ecf20Sopenharmony_ci	struct tipc_member *m, *rm, *pm;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	m = tipc_group_find_member(grp, node, port);
5978c2ecf20Sopenharmony_ci	if (!m)
5988c2ecf20Sopenharmony_ci		return;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	m->advertised -= blks;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	switch (m->state) {
6038c2ecf20Sopenharmony_ci	case MBR_JOINED:
6048c2ecf20Sopenharmony_ci		/* First, decide if member can go active */
6058c2ecf20Sopenharmony_ci		if (active_cnt <= max_active) {
6068c2ecf20Sopenharmony_ci			m->state = MBR_ACTIVE;
6078c2ecf20Sopenharmony_ci			list_add_tail(&m->list, active);
6088c2ecf20Sopenharmony_ci			grp->active_cnt++;
6098c2ecf20Sopenharmony_ci			tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
6108c2ecf20Sopenharmony_ci		} else {
6118c2ecf20Sopenharmony_ci			m->state = MBR_PENDING;
6128c2ecf20Sopenharmony_ci			list_add_tail(&m->list, &grp->pending);
6138c2ecf20Sopenharmony_ci		}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci		if (active_cnt < reclaim_limit)
6168c2ecf20Sopenharmony_ci			break;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci		/* Reclaim from oldest active member, if possible */
6198c2ecf20Sopenharmony_ci		if (!list_empty(active)) {
6208c2ecf20Sopenharmony_ci			rm = list_first_entry(active, struct tipc_member, list);
6218c2ecf20Sopenharmony_ci			rm->state = MBR_RECLAIMING;
6228c2ecf20Sopenharmony_ci			list_del_init(&rm->list);
6238c2ecf20Sopenharmony_ci			tipc_group_proto_xmit(grp, rm, GRP_RECLAIM_MSG, xmitq);
6248c2ecf20Sopenharmony_ci			break;
6258c2ecf20Sopenharmony_ci		}
6268c2ecf20Sopenharmony_ci		/* Nobody to reclaim from; - revert oldest pending to JOINED */
6278c2ecf20Sopenharmony_ci		pm = list_first_entry(&grp->pending, struct tipc_member, list);
6288c2ecf20Sopenharmony_ci		list_del_init(&pm->list);
6298c2ecf20Sopenharmony_ci		pm->state = MBR_JOINED;
6308c2ecf20Sopenharmony_ci		tipc_group_proto_xmit(grp, pm, GRP_ADV_MSG, xmitq);
6318c2ecf20Sopenharmony_ci		break;
6328c2ecf20Sopenharmony_ci	case MBR_ACTIVE:
6338c2ecf20Sopenharmony_ci		if (!list_is_last(&m->list, &grp->active))
6348c2ecf20Sopenharmony_ci			list_move_tail(&m->list, &grp->active);
6358c2ecf20Sopenharmony_ci		if (m->advertised > (ADV_ACTIVE * 3 / 4))
6368c2ecf20Sopenharmony_ci			break;
6378c2ecf20Sopenharmony_ci		tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
6388c2ecf20Sopenharmony_ci		break;
6398c2ecf20Sopenharmony_ci	case MBR_REMITTED:
6408c2ecf20Sopenharmony_ci		if (m->advertised > ADV_IDLE)
6418c2ecf20Sopenharmony_ci			break;
6428c2ecf20Sopenharmony_ci		m->state = MBR_JOINED;
6438c2ecf20Sopenharmony_ci		grp->active_cnt--;
6448c2ecf20Sopenharmony_ci		if (m->advertised < ADV_IDLE) {
6458c2ecf20Sopenharmony_ci			pr_warn_ratelimited("Rcv unexpected msg after REMIT\n");
6468c2ecf20Sopenharmony_ci			tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
6478c2ecf20Sopenharmony_ci		}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci		if (list_empty(&grp->pending))
6508c2ecf20Sopenharmony_ci			return;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci		/* Set oldest pending member to active and advertise */
6538c2ecf20Sopenharmony_ci		pm = list_first_entry(&grp->pending, struct tipc_member, list);
6548c2ecf20Sopenharmony_ci		pm->state = MBR_ACTIVE;
6558c2ecf20Sopenharmony_ci		list_move_tail(&pm->list, &grp->active);
6568c2ecf20Sopenharmony_ci		grp->active_cnt++;
6578c2ecf20Sopenharmony_ci		tipc_group_proto_xmit(grp, pm, GRP_ADV_MSG, xmitq);
6588c2ecf20Sopenharmony_ci		break;
6598c2ecf20Sopenharmony_ci	case MBR_RECLAIMING:
6608c2ecf20Sopenharmony_ci	case MBR_JOINING:
6618c2ecf20Sopenharmony_ci	case MBR_LEAVING:
6628c2ecf20Sopenharmony_ci	default:
6638c2ecf20Sopenharmony_ci		break;
6648c2ecf20Sopenharmony_ci	}
6658c2ecf20Sopenharmony_ci}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_cistatic void tipc_group_create_event(struct tipc_group *grp,
6688c2ecf20Sopenharmony_ci				    struct tipc_member *m,
6698c2ecf20Sopenharmony_ci				    u32 event, u16 seqno,
6708c2ecf20Sopenharmony_ci				    struct sk_buff_head *inputq)
6718c2ecf20Sopenharmony_ci{	u32 dnode = tipc_own_addr(grp->net);
6728c2ecf20Sopenharmony_ci	struct tipc_event evt;
6738c2ecf20Sopenharmony_ci	struct sk_buff *skb;
6748c2ecf20Sopenharmony_ci	struct tipc_msg *hdr;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	memset(&evt, 0, sizeof(evt));
6778c2ecf20Sopenharmony_ci	evt.event = event;
6788c2ecf20Sopenharmony_ci	evt.found_lower = m->instance;
6798c2ecf20Sopenharmony_ci	evt.found_upper = m->instance;
6808c2ecf20Sopenharmony_ci	evt.port.ref = m->port;
6818c2ecf20Sopenharmony_ci	evt.port.node = m->node;
6828c2ecf20Sopenharmony_ci	evt.s.seq.type = grp->type;
6838c2ecf20Sopenharmony_ci	evt.s.seq.lower = m->instance;
6848c2ecf20Sopenharmony_ci	evt.s.seq.upper = m->instance;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_GRP_MEMBER_EVT,
6878c2ecf20Sopenharmony_ci			      GROUP_H_SIZE, sizeof(evt), dnode, m->node,
6888c2ecf20Sopenharmony_ci			      grp->portid, m->port, 0);
6898c2ecf20Sopenharmony_ci	if (!skb)
6908c2ecf20Sopenharmony_ci		return;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	hdr = buf_msg(skb);
6938c2ecf20Sopenharmony_ci	msg_set_nametype(hdr, grp->type);
6948c2ecf20Sopenharmony_ci	msg_set_grp_evt(hdr, event);
6958c2ecf20Sopenharmony_ci	msg_set_dest_droppable(hdr, true);
6968c2ecf20Sopenharmony_ci	msg_set_grp_bc_seqno(hdr, seqno);
6978c2ecf20Sopenharmony_ci	memcpy(msg_data(hdr), &evt, sizeof(evt));
6988c2ecf20Sopenharmony_ci	TIPC_SKB_CB(skb)->orig_member = m->instance;
6998c2ecf20Sopenharmony_ci	__skb_queue_tail(inputq, skb);
7008c2ecf20Sopenharmony_ci}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_cistatic void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m,
7038c2ecf20Sopenharmony_ci				  int mtyp, struct sk_buff_head *xmitq)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	struct tipc_msg *hdr;
7068c2ecf20Sopenharmony_ci	struct sk_buff *skb;
7078c2ecf20Sopenharmony_ci	int adv = 0;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	skb = tipc_msg_create(GROUP_PROTOCOL, mtyp, INT_H_SIZE, 0,
7108c2ecf20Sopenharmony_ci			      m->node, tipc_own_addr(grp->net),
7118c2ecf20Sopenharmony_ci			      m->port, grp->portid, 0);
7128c2ecf20Sopenharmony_ci	if (!skb)
7138c2ecf20Sopenharmony_ci		return;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	if (m->state == MBR_ACTIVE)
7168c2ecf20Sopenharmony_ci		adv = ADV_ACTIVE - m->advertised;
7178c2ecf20Sopenharmony_ci	else if (m->state == MBR_JOINED || m->state == MBR_PENDING)
7188c2ecf20Sopenharmony_ci		adv = ADV_IDLE - m->advertised;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	hdr = buf_msg(skb);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	if (mtyp == GRP_JOIN_MSG) {
7238c2ecf20Sopenharmony_ci		msg_set_grp_bc_syncpt(hdr, grp->bc_snd_nxt);
7248c2ecf20Sopenharmony_ci		msg_set_adv_win(hdr, adv);
7258c2ecf20Sopenharmony_ci		m->advertised += adv;
7268c2ecf20Sopenharmony_ci	} else if (mtyp == GRP_LEAVE_MSG) {
7278c2ecf20Sopenharmony_ci		msg_set_grp_bc_syncpt(hdr, grp->bc_snd_nxt);
7288c2ecf20Sopenharmony_ci	} else if (mtyp == GRP_ADV_MSG) {
7298c2ecf20Sopenharmony_ci		msg_set_adv_win(hdr, adv);
7308c2ecf20Sopenharmony_ci		m->advertised += adv;
7318c2ecf20Sopenharmony_ci	} else if (mtyp == GRP_ACK_MSG) {
7328c2ecf20Sopenharmony_ci		msg_set_grp_bc_acked(hdr, m->bc_rcv_nxt);
7338c2ecf20Sopenharmony_ci	} else if (mtyp == GRP_REMIT_MSG) {
7348c2ecf20Sopenharmony_ci		msg_set_grp_remitted(hdr, m->window);
7358c2ecf20Sopenharmony_ci	}
7368c2ecf20Sopenharmony_ci	msg_set_dest_droppable(hdr, true);
7378c2ecf20Sopenharmony_ci	__skb_queue_tail(xmitq, skb);
7388c2ecf20Sopenharmony_ci}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_civoid tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
7418c2ecf20Sopenharmony_ci			  struct tipc_msg *hdr, struct sk_buff_head *inputq,
7428c2ecf20Sopenharmony_ci			  struct sk_buff_head *xmitq)
7438c2ecf20Sopenharmony_ci{
7448c2ecf20Sopenharmony_ci	u32 node = msg_orignode(hdr);
7458c2ecf20Sopenharmony_ci	u32 port = msg_origport(hdr);
7468c2ecf20Sopenharmony_ci	struct tipc_member *m, *pm;
7478c2ecf20Sopenharmony_ci	u16 remitted, in_flight;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	if (!grp)
7508c2ecf20Sopenharmony_ci		return;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	if (grp->scope == TIPC_NODE_SCOPE && node != tipc_own_addr(grp->net))
7538c2ecf20Sopenharmony_ci		return;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	m = tipc_group_find_member(grp, node, port);
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	switch (msg_type(hdr)) {
7588c2ecf20Sopenharmony_ci	case GRP_JOIN_MSG:
7598c2ecf20Sopenharmony_ci		if (!m)
7608c2ecf20Sopenharmony_ci			m = tipc_group_create_member(grp, node, port,
7618c2ecf20Sopenharmony_ci						     0, MBR_JOINING);
7628c2ecf20Sopenharmony_ci		if (!m)
7638c2ecf20Sopenharmony_ci			return;
7648c2ecf20Sopenharmony_ci		m->bc_syncpt = msg_grp_bc_syncpt(hdr);
7658c2ecf20Sopenharmony_ci		m->bc_rcv_nxt = m->bc_syncpt;
7668c2ecf20Sopenharmony_ci		m->window += msg_adv_win(hdr);
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci		/* Wait until PUBLISH event is received if necessary */
7698c2ecf20Sopenharmony_ci		if (m->state != MBR_PUBLISHED)
7708c2ecf20Sopenharmony_ci			return;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci		/* Member can be taken into service */
7738c2ecf20Sopenharmony_ci		m->state = MBR_JOINED;
7748c2ecf20Sopenharmony_ci		tipc_group_open(m, usr_wakeup);
7758c2ecf20Sopenharmony_ci		tipc_group_update_member(m, 0);
7768c2ecf20Sopenharmony_ci		tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
7778c2ecf20Sopenharmony_ci		tipc_group_create_event(grp, m, TIPC_PUBLISHED,
7788c2ecf20Sopenharmony_ci					m->bc_syncpt, inputq);
7798c2ecf20Sopenharmony_ci		return;
7808c2ecf20Sopenharmony_ci	case GRP_LEAVE_MSG:
7818c2ecf20Sopenharmony_ci		if (!m)
7828c2ecf20Sopenharmony_ci			return;
7838c2ecf20Sopenharmony_ci		m->bc_syncpt = msg_grp_bc_syncpt(hdr);
7848c2ecf20Sopenharmony_ci		list_del_init(&m->list);
7858c2ecf20Sopenharmony_ci		tipc_group_open(m, usr_wakeup);
7868c2ecf20Sopenharmony_ci		tipc_group_decr_active(grp, m);
7878c2ecf20Sopenharmony_ci		m->state = MBR_LEAVING;
7888c2ecf20Sopenharmony_ci		tipc_group_create_event(grp, m, TIPC_WITHDRAWN,
7898c2ecf20Sopenharmony_ci					m->bc_syncpt, inputq);
7908c2ecf20Sopenharmony_ci		return;
7918c2ecf20Sopenharmony_ci	case GRP_ADV_MSG:
7928c2ecf20Sopenharmony_ci		if (!m)
7938c2ecf20Sopenharmony_ci			return;
7948c2ecf20Sopenharmony_ci		m->window += msg_adv_win(hdr);
7958c2ecf20Sopenharmony_ci		tipc_group_open(m, usr_wakeup);
7968c2ecf20Sopenharmony_ci		return;
7978c2ecf20Sopenharmony_ci	case GRP_ACK_MSG:
7988c2ecf20Sopenharmony_ci		if (!m)
7998c2ecf20Sopenharmony_ci			return;
8008c2ecf20Sopenharmony_ci		m->bc_acked = msg_grp_bc_acked(hdr);
8018c2ecf20Sopenharmony_ci		if (--grp->bc_ackers)
8028c2ecf20Sopenharmony_ci			return;
8038c2ecf20Sopenharmony_ci		list_del_init(&m->small_win);
8048c2ecf20Sopenharmony_ci		*m->group->open = true;
8058c2ecf20Sopenharmony_ci		*usr_wakeup = true;
8068c2ecf20Sopenharmony_ci		tipc_group_update_member(m, 0);
8078c2ecf20Sopenharmony_ci		return;
8088c2ecf20Sopenharmony_ci	case GRP_RECLAIM_MSG:
8098c2ecf20Sopenharmony_ci		if (!m)
8108c2ecf20Sopenharmony_ci			return;
8118c2ecf20Sopenharmony_ci		tipc_group_proto_xmit(grp, m, GRP_REMIT_MSG, xmitq);
8128c2ecf20Sopenharmony_ci		m->window = ADV_IDLE;
8138c2ecf20Sopenharmony_ci		tipc_group_open(m, usr_wakeup);
8148c2ecf20Sopenharmony_ci		return;
8158c2ecf20Sopenharmony_ci	case GRP_REMIT_MSG:
8168c2ecf20Sopenharmony_ci		if (!m || m->state != MBR_RECLAIMING)
8178c2ecf20Sopenharmony_ci			return;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci		remitted = msg_grp_remitted(hdr);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci		/* Messages preceding the REMIT still in receive queue */
8228c2ecf20Sopenharmony_ci		if (m->advertised > remitted) {
8238c2ecf20Sopenharmony_ci			m->state = MBR_REMITTED;
8248c2ecf20Sopenharmony_ci			in_flight = m->advertised - remitted;
8258c2ecf20Sopenharmony_ci			m->advertised = ADV_IDLE + in_flight;
8268c2ecf20Sopenharmony_ci			return;
8278c2ecf20Sopenharmony_ci		}
8288c2ecf20Sopenharmony_ci		/* This should never happen */
8298c2ecf20Sopenharmony_ci		if (m->advertised < remitted)
8308c2ecf20Sopenharmony_ci			pr_warn_ratelimited("Unexpected REMIT msg\n");
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci		/* All messages preceding the REMIT have been read */
8338c2ecf20Sopenharmony_ci		m->state = MBR_JOINED;
8348c2ecf20Sopenharmony_ci		grp->active_cnt--;
8358c2ecf20Sopenharmony_ci		m->advertised = ADV_IDLE;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci		/* Set oldest pending member to active and advertise */
8388c2ecf20Sopenharmony_ci		if (list_empty(&grp->pending))
8398c2ecf20Sopenharmony_ci			return;
8408c2ecf20Sopenharmony_ci		pm = list_first_entry(&grp->pending, struct tipc_member, list);
8418c2ecf20Sopenharmony_ci		pm->state = MBR_ACTIVE;
8428c2ecf20Sopenharmony_ci		list_move_tail(&pm->list, &grp->active);
8438c2ecf20Sopenharmony_ci		grp->active_cnt++;
8448c2ecf20Sopenharmony_ci		if (pm->advertised <= (ADV_ACTIVE * 3 / 4))
8458c2ecf20Sopenharmony_ci			tipc_group_proto_xmit(grp, pm, GRP_ADV_MSG, xmitq);
8468c2ecf20Sopenharmony_ci		return;
8478c2ecf20Sopenharmony_ci	default:
8488c2ecf20Sopenharmony_ci		pr_warn("Received unknown GROUP_PROTO message\n");
8498c2ecf20Sopenharmony_ci	}
8508c2ecf20Sopenharmony_ci}
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci/* tipc_group_member_evt() - receive and handle a member up/down event
8538c2ecf20Sopenharmony_ci */
8548c2ecf20Sopenharmony_civoid tipc_group_member_evt(struct tipc_group *grp,
8558c2ecf20Sopenharmony_ci			   bool *usr_wakeup,
8568c2ecf20Sopenharmony_ci			   int *sk_rcvbuf,
8578c2ecf20Sopenharmony_ci			   struct tipc_msg *hdr,
8588c2ecf20Sopenharmony_ci			   struct sk_buff_head *inputq,
8598c2ecf20Sopenharmony_ci			   struct sk_buff_head *xmitq)
8608c2ecf20Sopenharmony_ci{
8618c2ecf20Sopenharmony_ci	struct tipc_event *evt = (void *)msg_data(hdr);
8628c2ecf20Sopenharmony_ci	u32 instance = evt->found_lower;
8638c2ecf20Sopenharmony_ci	u32 node = evt->port.node;
8648c2ecf20Sopenharmony_ci	u32 port = evt->port.ref;
8658c2ecf20Sopenharmony_ci	int event = evt->event;
8668c2ecf20Sopenharmony_ci	struct tipc_member *m;
8678c2ecf20Sopenharmony_ci	struct net *net;
8688c2ecf20Sopenharmony_ci	u32 self;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	if (!grp)
8718c2ecf20Sopenharmony_ci		return;
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	net = grp->net;
8748c2ecf20Sopenharmony_ci	self = tipc_own_addr(net);
8758c2ecf20Sopenharmony_ci	if (!grp->loopback && node == self && port == grp->portid)
8768c2ecf20Sopenharmony_ci		return;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	m = tipc_group_find_member(grp, node, port);
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	switch (event) {
8818c2ecf20Sopenharmony_ci	case TIPC_PUBLISHED:
8828c2ecf20Sopenharmony_ci		/* Send and wait for arrival of JOIN message if necessary */
8838c2ecf20Sopenharmony_ci		if (!m) {
8848c2ecf20Sopenharmony_ci			m = tipc_group_create_member(grp, node, port, instance,
8858c2ecf20Sopenharmony_ci						     MBR_PUBLISHED);
8868c2ecf20Sopenharmony_ci			if (!m)
8878c2ecf20Sopenharmony_ci				break;
8888c2ecf20Sopenharmony_ci			tipc_group_update_member(m, 0);
8898c2ecf20Sopenharmony_ci			tipc_group_proto_xmit(grp, m, GRP_JOIN_MSG, xmitq);
8908c2ecf20Sopenharmony_ci			break;
8918c2ecf20Sopenharmony_ci		}
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci		if (m->state != MBR_JOINING)
8948c2ecf20Sopenharmony_ci			break;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci		/* Member can be taken into service */
8978c2ecf20Sopenharmony_ci		m->instance = instance;
8988c2ecf20Sopenharmony_ci		m->state = MBR_JOINED;
8998c2ecf20Sopenharmony_ci		tipc_group_open(m, usr_wakeup);
9008c2ecf20Sopenharmony_ci		tipc_group_update_member(m, 0);
9018c2ecf20Sopenharmony_ci		tipc_group_proto_xmit(grp, m, GRP_JOIN_MSG, xmitq);
9028c2ecf20Sopenharmony_ci		tipc_group_create_event(grp, m, TIPC_PUBLISHED,
9038c2ecf20Sopenharmony_ci					m->bc_syncpt, inputq);
9048c2ecf20Sopenharmony_ci		break;
9058c2ecf20Sopenharmony_ci	case TIPC_WITHDRAWN:
9068c2ecf20Sopenharmony_ci		if (!m)
9078c2ecf20Sopenharmony_ci			break;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci		tipc_group_decr_active(grp, m);
9108c2ecf20Sopenharmony_ci		m->state = MBR_LEAVING;
9118c2ecf20Sopenharmony_ci		list_del_init(&m->list);
9128c2ecf20Sopenharmony_ci		tipc_group_open(m, usr_wakeup);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci		/* Only send event if no LEAVE message can be expected */
9158c2ecf20Sopenharmony_ci		if (!tipc_node_is_up(net, node))
9168c2ecf20Sopenharmony_ci			tipc_group_create_event(grp, m, TIPC_WITHDRAWN,
9178c2ecf20Sopenharmony_ci						m->bc_rcv_nxt, inputq);
9188c2ecf20Sopenharmony_ci		break;
9198c2ecf20Sopenharmony_ci	default:
9208c2ecf20Sopenharmony_ci		break;
9218c2ecf20Sopenharmony_ci	}
9228c2ecf20Sopenharmony_ci	*sk_rcvbuf = tipc_group_rcvbuf_limit(grp);
9238c2ecf20Sopenharmony_ci}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ciint tipc_group_fill_sock_diag(struct tipc_group *grp, struct sk_buff *skb)
9268c2ecf20Sopenharmony_ci{
9278c2ecf20Sopenharmony_ci	struct nlattr *group = nla_nest_start_noflag(skb, TIPC_NLA_SOCK_GROUP);
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	if (!group)
9308c2ecf20Sopenharmony_ci		return -EMSGSIZE;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, TIPC_NLA_SOCK_GROUP_ID,
9338c2ecf20Sopenharmony_ci			grp->type) ||
9348c2ecf20Sopenharmony_ci	    nla_put_u32(skb, TIPC_NLA_SOCK_GROUP_INSTANCE,
9358c2ecf20Sopenharmony_ci			grp->instance) ||
9368c2ecf20Sopenharmony_ci	    nla_put_u32(skb, TIPC_NLA_SOCK_GROUP_BC_SEND_NEXT,
9378c2ecf20Sopenharmony_ci			grp->bc_snd_nxt))
9388c2ecf20Sopenharmony_ci		goto group_msg_cancel;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	if (grp->scope == TIPC_NODE_SCOPE)
9418c2ecf20Sopenharmony_ci		if (nla_put_flag(skb, TIPC_NLA_SOCK_GROUP_NODE_SCOPE))
9428c2ecf20Sopenharmony_ci			goto group_msg_cancel;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	if (grp->scope == TIPC_CLUSTER_SCOPE)
9458c2ecf20Sopenharmony_ci		if (nla_put_flag(skb, TIPC_NLA_SOCK_GROUP_CLUSTER_SCOPE))
9468c2ecf20Sopenharmony_ci			goto group_msg_cancel;
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	if (*grp->open)
9498c2ecf20Sopenharmony_ci		if (nla_put_flag(skb, TIPC_NLA_SOCK_GROUP_OPEN))
9508c2ecf20Sopenharmony_ci			goto group_msg_cancel;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	nla_nest_end(skb, group);
9538c2ecf20Sopenharmony_ci	return 0;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_cigroup_msg_cancel:
9568c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, group);
9578c2ecf20Sopenharmony_ci	return -1;
9588c2ecf20Sopenharmony_ci}
959