/*
* net/tipc/name_table.c: TIPC name table code
*
* Copyright (c) 2000-2006, 2014-2018, Ericsson AB
* Copyright (c) 2004-2008, 2010-2014, Wind River Systems
* Copyright (c) 2020-2021, Red Hat Inc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <net/sock.h>
#include <linux/list_sort.h>
#include <linux/rbtree_augmented.h>
#include "core.h"
#include "netlink.h"
#include "name_table.h"
#include "name_distr.h"
#include "subscr.h"
#include "bcast.h"
#include "addr.h"
#include "node.h"
#include "group.h"
/**
* struct service_range - container for all bindings of a service range
* @lower: service range lower bound
* @upper: service range upper bound
* @tree_node: member of service range RB tree
* @max: largest 'upper' in this node subtree
* @local_publ: list of identical publications made from this node
* Used by closest_first lookup and multicast lookup algorithm
* @all_publ: all publications identical to this one, whatever node and scope
* Used by round-robin lookup algorithm
*/
struct service_range {
u32 lower;
u32 upper;
struct rb_node tree_node;
u32 max;
struct list_head local_publ;
struct list_head all_publ;
};
/**
* struct tipc_service - container for all published instances of a service type
* @type: 32 bit 'type' value for service
* @publ_cnt: increasing counter for publications in this service
* @ranges: rb tree containing all service ranges for this service
* @service_list: links to adjacent name ranges in hash chain
* @subscriptions: list of subscriptions for this service type
* @lock: spinlock controlling access to pertaining service ranges/publications
* @rcu: RCU callback head used for deferred freeing
*/
struct tipc_service {
u32 type;
u32 publ_cnt;
struct rb_root ranges;
struct hlist_node service_list;
struct list_head subscriptions;
spinlock_t lock; /* Covers service range list */
struct rcu_head rcu;
};
#define service_range_upper(sr) ((sr)->upper)
RB_DECLARE_CALLBACKS_MAX(static, sr_callbacks,
struct service_range, tree_node, u32, max,
service_range_upper)
#define service_range_entry(rbtree_node) \
(container_of(rbtree_node, struct service_range, tree_node))
#define service_range_overlap(sr, start, end) \
((sr)->lower <= (end) && (sr)->upper >= (start))
/**
* service_range_foreach_match - iterate over tipc service rbtree for each
* range match
* @sr: the service range pointer as a loop cursor
* @sc: the pointer to tipc service which holds the service range rbtree
* @start: beginning of the search range (end >= start) for matching
* @end: end of the search range (end >= start) for matching
*/
#define service_range_foreach_match(sr, sc, start, end) \
for (sr = service_range_match_first((sc)->ranges.rb_node, \
start, \
end); \
sr; \
sr = service_range_match_next(&(sr)->tree_node, \
start, \
end))
/**
* service_range_match_first - find first service range matching a range
* @n: the root node of service range rbtree for searching
* @start: beginning of the search range (end >= start) for matching
* @end: end of the search range (end >= start) for matching
*
* Return: the leftmost service range node in the rbtree that overlaps the
* specific range if any. Otherwise, returns NULL.
*/
static struct service_range *service_range_match_first(struct rb_node *n,
u32 start, u32 end)
{
struct service_range *sr;
struct rb_node *l, *r;
/* Non overlaps in tree at all? */
if (!n || service_range_entry(n)->max < start)
return NULL;
while (n) {
l = n->rb_left;
if (l && service_range_entry(l)->max >= start) {
/* A leftmost overlap range node must be one in the left
* subtree. If not, it has lower > end, then nodes on
* the right side cannot satisfy the condition either.
*/
n = l;
continue;
}
/* No one in the left subtree can match, return if this node is
* an overlap i.e. leftmost.
*/
sr = service_range_entry(n);
if (service_range_overlap(sr, start, end))
return sr;
/* Ok, try to lookup on the right side */
r = n->rb_right;
if (sr->lower <= end &&
r && service_range_entry(r)->max >= start) {
n = r;
continue;
}
break;
}
return NULL;
}
/**
* service_range_match_next - find next service range matching a range
* @n: a node in service range rbtree from which the searching starts
* @start: beginning of the search range (end >= start) for matching
* @end: end of the search range (end >= start) for matching
*
* Return: the next service range node to the given node in the rbtree that
* overlaps the specific range if any. Otherwise, returns NULL.
*/
static struct service_range *service_range_match_next(struct rb_