18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * net/tipc/subscr.c: TIPC network topology service
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (c) 2000-2017, Ericsson AB
58c2ecf20Sopenharmony_ci * Copyright (c) 2005-2007, 2010-2013, Wind River Systems
68c2ecf20Sopenharmony_ci * All rights reserved.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
98c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
128c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
148c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
158c2ecf20Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
168c2ecf20Sopenharmony_ci * 3. Neither the names of the copyright holders nor the names of its
178c2ecf20Sopenharmony_ci *    contributors may be used to endorse or promote products derived from
188c2ecf20Sopenharmony_ci *    this software without specific prior written permission.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the
218c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free
228c2ecf20Sopenharmony_ci * Software Foundation.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
258c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
268c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
278c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
288c2ecf20Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
298c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
308c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
318c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
328c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
338c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
348c2ecf20Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include "core.h"
388c2ecf20Sopenharmony_ci#include "name_table.h"
398c2ecf20Sopenharmony_ci#include "subscr.h"
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic void tipc_sub_send_event(struct tipc_subscription *sub,
428c2ecf20Sopenharmony_ci				u32 found_lower, u32 found_upper,
438c2ecf20Sopenharmony_ci				u32 event, u32 port, u32 node)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct tipc_event *evt = &sub->evt;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (sub->inactive)
488c2ecf20Sopenharmony_ci		return;
498c2ecf20Sopenharmony_ci	tipc_evt_write(evt, event, event);
508c2ecf20Sopenharmony_ci	tipc_evt_write(evt, found_lower, found_lower);
518c2ecf20Sopenharmony_ci	tipc_evt_write(evt, found_upper, found_upper);
528c2ecf20Sopenharmony_ci	tipc_evt_write(evt, port.ref, port);
538c2ecf20Sopenharmony_ci	tipc_evt_write(evt, port.node, node);
548c2ecf20Sopenharmony_ci	tipc_topsrv_queue_evt(sub->net, sub->conid, event, evt);
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/**
588c2ecf20Sopenharmony_ci * tipc_sub_check_overlap - test for subscription overlap with the
598c2ecf20Sopenharmony_ci * given values
608c2ecf20Sopenharmony_ci *
618c2ecf20Sopenharmony_ci * Returns 1 if there is overlap, otherwise 0.
628c2ecf20Sopenharmony_ci */
638c2ecf20Sopenharmony_ciint tipc_sub_check_overlap(struct tipc_name_seq *seq, u32 found_lower,
648c2ecf20Sopenharmony_ci			   u32 found_upper)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	if (found_lower < seq->lower)
678c2ecf20Sopenharmony_ci		found_lower = seq->lower;
688c2ecf20Sopenharmony_ci	if (found_upper > seq->upper)
698c2ecf20Sopenharmony_ci		found_upper = seq->upper;
708c2ecf20Sopenharmony_ci	if (found_lower > found_upper)
718c2ecf20Sopenharmony_ci		return 0;
728c2ecf20Sopenharmony_ci	return 1;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_civoid tipc_sub_report_overlap(struct tipc_subscription *sub,
768c2ecf20Sopenharmony_ci			     u32 found_lower, u32 found_upper,
778c2ecf20Sopenharmony_ci			     u32 event, u32 port, u32 node,
788c2ecf20Sopenharmony_ci			     u32 scope, int must)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	struct tipc_subscr *s = &sub->evt.s;
818c2ecf20Sopenharmony_ci	u32 filter = tipc_sub_read(s, filter);
828c2ecf20Sopenharmony_ci	struct tipc_name_seq seq;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	seq.type = tipc_sub_read(s, seq.type);
858c2ecf20Sopenharmony_ci	seq.lower = tipc_sub_read(s, seq.lower);
868c2ecf20Sopenharmony_ci	seq.upper = tipc_sub_read(s, seq.upper);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if (!tipc_sub_check_overlap(&seq, found_lower, found_upper))
898c2ecf20Sopenharmony_ci		return;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (!must && !(filter & TIPC_SUB_PORTS))
928c2ecf20Sopenharmony_ci		return;
938c2ecf20Sopenharmony_ci	if (filter & TIPC_SUB_CLUSTER_SCOPE && scope == TIPC_NODE_SCOPE)
948c2ecf20Sopenharmony_ci		return;
958c2ecf20Sopenharmony_ci	if (filter & TIPC_SUB_NODE_SCOPE && scope != TIPC_NODE_SCOPE)
968c2ecf20Sopenharmony_ci		return;
978c2ecf20Sopenharmony_ci	spin_lock(&sub->lock);
988c2ecf20Sopenharmony_ci	tipc_sub_send_event(sub, found_lower, found_upper,
998c2ecf20Sopenharmony_ci			    event, port, node);
1008c2ecf20Sopenharmony_ci	spin_unlock(&sub->lock);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic void tipc_sub_timeout(struct timer_list *t)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	struct tipc_subscription *sub = from_timer(sub, t, timer);
1068c2ecf20Sopenharmony_ci	struct tipc_subscr *s = &sub->evt.s;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	spin_lock(&sub->lock);
1098c2ecf20Sopenharmony_ci	tipc_sub_send_event(sub, s->seq.lower, s->seq.upper,
1108c2ecf20Sopenharmony_ci			    TIPC_SUBSCR_TIMEOUT, 0, 0);
1118c2ecf20Sopenharmony_ci	sub->inactive = true;
1128c2ecf20Sopenharmony_ci	spin_unlock(&sub->lock);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic void tipc_sub_kref_release(struct kref *kref)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	kfree(container_of(kref, struct tipc_subscription, kref));
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_civoid tipc_sub_put(struct tipc_subscription *subscription)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	kref_put(&subscription->kref, tipc_sub_kref_release);
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_civoid tipc_sub_get(struct tipc_subscription *subscription)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	kref_get(&subscription->kref);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistruct tipc_subscription *tipc_sub_subscribe(struct net *net,
1318c2ecf20Sopenharmony_ci					     struct tipc_subscr *s,
1328c2ecf20Sopenharmony_ci					     int conid)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	u32 filter = tipc_sub_read(s, filter);
1358c2ecf20Sopenharmony_ci	struct tipc_subscription *sub;
1368c2ecf20Sopenharmony_ci	u32 timeout;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	if ((filter & TIPC_SUB_PORTS && filter & TIPC_SUB_SERVICE) ||
1398c2ecf20Sopenharmony_ci	    (tipc_sub_read(s, seq.lower) > tipc_sub_read(s, seq.upper))) {
1408c2ecf20Sopenharmony_ci		pr_warn("Subscription rejected, illegal request\n");
1418c2ecf20Sopenharmony_ci		return NULL;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci	sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
1448c2ecf20Sopenharmony_ci	if (!sub) {
1458c2ecf20Sopenharmony_ci		pr_warn("Subscription rejected, no memory\n");
1468c2ecf20Sopenharmony_ci		return NULL;
1478c2ecf20Sopenharmony_ci	}
1488c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&sub->service_list);
1498c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&sub->sub_list);
1508c2ecf20Sopenharmony_ci	sub->net = net;
1518c2ecf20Sopenharmony_ci	sub->conid = conid;
1528c2ecf20Sopenharmony_ci	sub->inactive = false;
1538c2ecf20Sopenharmony_ci	memcpy(&sub->evt.s, s, sizeof(*s));
1548c2ecf20Sopenharmony_ci	spin_lock_init(&sub->lock);
1558c2ecf20Sopenharmony_ci	kref_init(&sub->kref);
1568c2ecf20Sopenharmony_ci	if (!tipc_nametbl_subscribe(sub)) {
1578c2ecf20Sopenharmony_ci		kfree(sub);
1588c2ecf20Sopenharmony_ci		return NULL;
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci	timer_setup(&sub->timer, tipc_sub_timeout, 0);
1618c2ecf20Sopenharmony_ci	timeout = tipc_sub_read(&sub->evt.s, timeout);
1628c2ecf20Sopenharmony_ci	if (timeout != TIPC_WAIT_FOREVER)
1638c2ecf20Sopenharmony_ci		mod_timer(&sub->timer, jiffies + msecs_to_jiffies(timeout));
1648c2ecf20Sopenharmony_ci	return sub;
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_civoid tipc_sub_unsubscribe(struct tipc_subscription *sub)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	tipc_nametbl_unsubscribe(sub);
1708c2ecf20Sopenharmony_ci	if (sub->evt.s.timeout != TIPC_WAIT_FOREVER)
1718c2ecf20Sopenharmony_ci		del_timer_sync(&sub->timer);
1728c2ecf20Sopenharmony_ci	list_del(&sub->sub_list);
1738c2ecf20Sopenharmony_ci	tipc_sub_put(sub);
1748c2ecf20Sopenharmony_ci}
175