1 | /* |
2 | * net/tipc/subscr.c: TIPC network topology service |
3 | * |
4 | * Copyright (c) 2000-2017, Ericsson AB |
5 | * Copyright (c) 2005-2007, 2010-2013, Wind River Systems |
6 | * Copyright (c) 2020-2021, Red Hat Inc |
7 | * All rights reserved. |
8 | * |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions are met: |
11 | * |
12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. Neither the names of the copyright holders nor the names of its |
18 | * contributors may be used to endorse or promote products derived from |
19 | * this software without specific prior written permission. |
20 | * |
21 | * Alternatively, this software may be distributed under the terms of the |
22 | * GNU General Public License ("GPL") version 2 as published by the Free |
23 | * Software Foundation. |
24 | * |
25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
35 | * POSSIBILITY OF SUCH DAMAGE. |
36 | */ |
37 | |
38 | #include "core.h" |
39 | #include "name_table.h" |
40 | #include "subscr.h" |
41 | |
42 | static void tipc_sub_send_event(struct tipc_subscription *sub, |
43 | struct publication *p, |
44 | u32 event) |
45 | { |
46 | struct tipc_subscr *s = &sub->evt.s; |
47 | struct tipc_event *evt = &sub->evt; |
48 | |
49 | if (sub->inactive) |
50 | return; |
51 | tipc_evt_write(evt, event, event); |
52 | if (p) { |
53 | tipc_evt_write(evt, found_lower, p->sr.lower); |
54 | tipc_evt_write(evt, found_upper, p->sr.upper); |
55 | tipc_evt_write(evt, port.ref, p->sk.ref); |
56 | tipc_evt_write(evt, port.node, p->sk.node); |
57 | } else { |
58 | tipc_evt_write(evt, found_lower, s->seq.lower); |
59 | tipc_evt_write(evt, found_upper, s->seq.upper); |
60 | tipc_evt_write(evt, port.ref, 0); |
61 | tipc_evt_write(evt, port.node, 0); |
62 | } |
63 | tipc_topsrv_queue_evt(net: sub->net, conid: sub->conid, event, evt); |
64 | } |
65 | |
66 | /** |
67 | * tipc_sub_check_overlap - test for subscription overlap with the given values |
68 | * @subscribed: the service range subscribed for |
69 | * @found: the service range we are checking for match |
70 | * |
71 | * Returns true if there is overlap, otherwise false. |
72 | */ |
73 | static bool tipc_sub_check_overlap(struct tipc_service_range *subscribed, |
74 | struct tipc_service_range *found) |
75 | { |
76 | u32 found_lower = found->lower; |
77 | u32 found_upper = found->upper; |
78 | |
79 | if (found_lower < subscribed->lower) |
80 | found_lower = subscribed->lower; |
81 | if (found_upper > subscribed->upper) |
82 | found_upper = subscribed->upper; |
83 | return found_lower <= found_upper; |
84 | } |
85 | |
86 | void tipc_sub_report_overlap(struct tipc_subscription *sub, |
87 | struct publication *p, |
88 | u32 event, bool must) |
89 | { |
90 | struct tipc_service_range *sr = &sub->s.seq; |
91 | u32 filter = sub->s.filter; |
92 | |
93 | if (!tipc_sub_check_overlap(subscribed: sr, found: &p->sr)) |
94 | return; |
95 | if (!must && !(filter & TIPC_SUB_PORTS)) |
96 | return; |
97 | if (filter & TIPC_SUB_CLUSTER_SCOPE && p->scope == TIPC_NODE_SCOPE) |
98 | return; |
99 | if (filter & TIPC_SUB_NODE_SCOPE && p->scope != TIPC_NODE_SCOPE) |
100 | return; |
101 | spin_lock(lock: &sub->lock); |
102 | tipc_sub_send_event(sub, p, event); |
103 | spin_unlock(lock: &sub->lock); |
104 | } |
105 | |
106 | static void tipc_sub_timeout(struct timer_list *t) |
107 | { |
108 | struct tipc_subscription *sub = from_timer(sub, t, timer); |
109 | |
110 | spin_lock(lock: &sub->lock); |
111 | tipc_sub_send_event(sub, NULL, TIPC_SUBSCR_TIMEOUT); |
112 | sub->inactive = true; |
113 | spin_unlock(lock: &sub->lock); |
114 | } |
115 | |
116 | static void tipc_sub_kref_release(struct kref *kref) |
117 | { |
118 | kfree(container_of(kref, struct tipc_subscription, kref)); |
119 | } |
120 | |
121 | void tipc_sub_put(struct tipc_subscription *subscription) |
122 | { |
123 | kref_put(kref: &subscription->kref, release: tipc_sub_kref_release); |
124 | } |
125 | |
126 | void tipc_sub_get(struct tipc_subscription *subscription) |
127 | { |
128 | kref_get(kref: &subscription->kref); |
129 | } |
130 | |
131 | struct tipc_subscription *tipc_sub_subscribe(struct net *net, |
132 | struct tipc_subscr *s, |
133 | int conid) |
134 | { |
135 | u32 lower = tipc_sub_read(s, seq.lower); |
136 | u32 upper = tipc_sub_read(s, seq.upper); |
137 | u32 filter = tipc_sub_read(s, filter); |
138 | struct tipc_subscription *sub; |
139 | u32 timeout; |
140 | |
141 | if ((filter & TIPC_SUB_PORTS && filter & TIPC_SUB_SERVICE) || |
142 | lower > upper) { |
143 | pr_warn("Subscription rejected, illegal request\n" ); |
144 | return NULL; |
145 | } |
146 | sub = kmalloc(size: sizeof(*sub), GFP_ATOMIC); |
147 | if (!sub) { |
148 | pr_warn("Subscription rejected, no memory\n" ); |
149 | return NULL; |
150 | } |
151 | INIT_LIST_HEAD(list: &sub->service_list); |
152 | INIT_LIST_HEAD(list: &sub->sub_list); |
153 | sub->net = net; |
154 | sub->conid = conid; |
155 | sub->inactive = false; |
156 | memcpy(&sub->evt.s, s, sizeof(*s)); |
157 | sub->s.seq.type = tipc_sub_read(s, seq.type); |
158 | sub->s.seq.lower = lower; |
159 | sub->s.seq.upper = upper; |
160 | sub->s.filter = filter; |
161 | sub->s.timeout = tipc_sub_read(s, timeout); |
162 | memcpy(sub->s.usr_handle, s->usr_handle, 8); |
163 | spin_lock_init(&sub->lock); |
164 | kref_init(kref: &sub->kref); |
165 | if (!tipc_nametbl_subscribe(s: sub)) { |
166 | kfree(objp: sub); |
167 | return NULL; |
168 | } |
169 | timer_setup(&sub->timer, tipc_sub_timeout, 0); |
170 | timeout = tipc_sub_read(&sub->evt.s, timeout); |
171 | if (timeout != TIPC_WAIT_FOREVER) |
172 | mod_timer(timer: &sub->timer, expires: jiffies + msecs_to_jiffies(m: timeout)); |
173 | return sub; |
174 | } |
175 | |
176 | void tipc_sub_unsubscribe(struct tipc_subscription *sub) |
177 | { |
178 | tipc_nametbl_unsubscribe(s: sub); |
179 | if (sub->evt.s.timeout != TIPC_WAIT_FOREVER) |
180 | del_timer_sync(timer: &sub->timer); |
181 | list_del(entry: &sub->sub_list); |
182 | tipc_sub_put(subscription: sub); |
183 | } |
184 | |