diff options
Diffstat (limited to 'net/tipc/subscr.c')
-rw-r--r-- | net/tipc/subscr.c | 132 |
1 files changed, 81 insertions, 51 deletions
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index f9ff73a8d815..e6cb386fbf34 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c | |||
@@ -92,25 +92,42 @@ static void tipc_subscrp_send_event(struct tipc_subscription *sub, | |||
92 | * | 92 | * |
93 | * Returns 1 if there is overlap, otherwise 0. | 93 | * Returns 1 if there is overlap, otherwise 0. |
94 | */ | 94 | */ |
95 | int tipc_subscrp_check_overlap(struct tipc_subscription *sub, u32 found_lower, | 95 | int tipc_subscrp_check_overlap(struct tipc_name_seq *seq, u32 found_lower, |
96 | u32 found_upper) | 96 | u32 found_upper) |
97 | { | 97 | { |
98 | if (found_lower < sub->seq.lower) | 98 | if (found_lower < seq->lower) |
99 | found_lower = sub->seq.lower; | 99 | found_lower = seq->lower; |
100 | if (found_upper > sub->seq.upper) | 100 | if (found_upper > seq->upper) |
101 | found_upper = sub->seq.upper; | 101 | found_upper = seq->upper; |
102 | if (found_lower > found_upper) | 102 | if (found_lower > found_upper) |
103 | return 0; | 103 | return 0; |
104 | return 1; | 104 | return 1; |
105 | } | 105 | } |
106 | 106 | ||
107 | u32 tipc_subscrp_convert_seq_type(u32 type, int swap) | ||
108 | { | ||
109 | return htohl(type, swap); | ||
110 | } | ||
111 | |||
112 | void tipc_subscrp_convert_seq(struct tipc_name_seq *in, int swap, | ||
113 | struct tipc_name_seq *out) | ||
114 | { | ||
115 | out->type = htohl(in->type, swap); | ||
116 | out->lower = htohl(in->lower, swap); | ||
117 | out->upper = htohl(in->upper, swap); | ||
118 | } | ||
119 | |||
107 | void tipc_subscrp_report_overlap(struct tipc_subscription *sub, u32 found_lower, | 120 | void tipc_subscrp_report_overlap(struct tipc_subscription *sub, u32 found_lower, |
108 | u32 found_upper, u32 event, u32 port_ref, | 121 | u32 found_upper, u32 event, u32 port_ref, |
109 | u32 node, int must) | 122 | u32 node, int must) |
110 | { | 123 | { |
111 | if (!tipc_subscrp_check_overlap(sub, found_lower, found_upper)) | 124 | struct tipc_name_seq seq; |
125 | |||
126 | tipc_subscrp_convert_seq(&sub->evt.s.seq, sub->swap, &seq); | ||
127 | if (!tipc_subscrp_check_overlap(&seq, found_lower, found_upper)) | ||
112 | return; | 128 | return; |
113 | if (!must && !(sub->filter & TIPC_SUB_PORTS)) | 129 | if (!must && |
130 | !(htohl(sub->evt.s.filter, sub->swap) & TIPC_SUB_PORTS)) | ||
114 | return; | 131 | return; |
115 | 132 | ||
116 | tipc_subscrp_send_event(sub, found_lower, found_upper, event, port_ref, | 133 | tipc_subscrp_send_event(sub, found_lower, found_upper, event, port_ref, |
@@ -171,12 +188,14 @@ static struct tipc_subscriber *tipc_subscrb_create(int conid) | |||
171 | static void tipc_subscrb_delete(struct tipc_subscriber *subscriber) | 188 | static void tipc_subscrb_delete(struct tipc_subscriber *subscriber) |
172 | { | 189 | { |
173 | struct tipc_subscription *sub, *temp; | 190 | struct tipc_subscription *sub, *temp; |
191 | u32 timeout; | ||
174 | 192 | ||
175 | spin_lock_bh(&subscriber->lock); | 193 | spin_lock_bh(&subscriber->lock); |
176 | /* Destroy any existing subscriptions for subscriber */ | 194 | /* Destroy any existing subscriptions for subscriber */ |
177 | list_for_each_entry_safe(sub, temp, &subscriber->subscrp_list, | 195 | list_for_each_entry_safe(sub, temp, &subscriber->subscrp_list, |
178 | subscrp_list) { | 196 | subscrp_list) { |
179 | if (del_timer(&sub->timer)) { | 197 | timeout = htohl(sub->evt.s.timeout, sub->swap); |
198 | if ((timeout == TIPC_WAIT_FOREVER) || del_timer(&sub->timer)) { | ||
180 | tipc_subscrp_delete(sub); | 199 | tipc_subscrp_delete(sub); |
181 | tipc_subscrb_put(subscriber); | 200 | tipc_subscrb_put(subscriber); |
182 | } | 201 | } |
@@ -200,13 +219,16 @@ static void tipc_subscrp_cancel(struct tipc_subscr *s, | |||
200 | struct tipc_subscriber *subscriber) | 219 | struct tipc_subscriber *subscriber) |
201 | { | 220 | { |
202 | struct tipc_subscription *sub, *temp; | 221 | struct tipc_subscription *sub, *temp; |
222 | u32 timeout; | ||
203 | 223 | ||
204 | spin_lock_bh(&subscriber->lock); | 224 | spin_lock_bh(&subscriber->lock); |
205 | /* Find first matching subscription, exit if not found */ | 225 | /* Find first matching subscription, exit if not found */ |
206 | list_for_each_entry_safe(sub, temp, &subscriber->subscrp_list, | 226 | list_for_each_entry_safe(sub, temp, &subscriber->subscrp_list, |
207 | subscrp_list) { | 227 | subscrp_list) { |
208 | if (!memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr))) { | 228 | if (!memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr))) { |
209 | if (del_timer(&sub->timer)) { | 229 | timeout = htohl(sub->evt.s.timeout, sub->swap); |
230 | if ((timeout == TIPC_WAIT_FOREVER) || | ||
231 | del_timer(&sub->timer)) { | ||
210 | tipc_subscrp_delete(sub); | 232 | tipc_subscrp_delete(sub); |
211 | tipc_subscrb_put(subscriber); | 233 | tipc_subscrb_put(subscriber); |
212 | } | 234 | } |
@@ -216,66 +238,67 @@ static void tipc_subscrp_cancel(struct tipc_subscr *s, | |||
216 | spin_unlock_bh(&subscriber->lock); | 238 | spin_unlock_bh(&subscriber->lock); |
217 | } | 239 | } |
218 | 240 | ||
219 | static int tipc_subscrp_create(struct net *net, struct tipc_subscr *s, | 241 | static struct tipc_subscription *tipc_subscrp_create(struct net *net, |
220 | struct tipc_subscriber *subscriber, | 242 | struct tipc_subscr *s, |
221 | struct tipc_subscription **sub_p) | 243 | int swap) |
222 | { | 244 | { |
223 | struct tipc_net *tn = net_generic(net, tipc_net_id); | 245 | struct tipc_net *tn = net_generic(net, tipc_net_id); |
224 | struct tipc_subscription *sub; | 246 | struct tipc_subscription *sub; |
225 | int swap; | 247 | u32 filter = htohl(s->filter, swap); |
226 | |||
227 | /* Determine subscriber's endianness */ | ||
228 | swap = !(s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE)); | ||
229 | |||
230 | /* Detect & process a subscription cancellation request */ | ||
231 | if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) { | ||
232 | s->filter &= ~htohl(TIPC_SUB_CANCEL, swap); | ||
233 | tipc_subscrp_cancel(s, subscriber); | ||
234 | return 0; | ||
235 | } | ||
236 | 248 | ||
237 | /* Refuse subscription if global limit exceeded */ | 249 | /* Refuse subscription if global limit exceeded */ |
238 | if (atomic_read(&tn->subscription_count) >= TIPC_MAX_SUBSCRIPTIONS) { | 250 | if (atomic_read(&tn->subscription_count) >= TIPC_MAX_SUBSCRIPTIONS) { |
239 | pr_warn("Subscription rejected, limit reached (%u)\n", | 251 | pr_warn("Subscription rejected, limit reached (%u)\n", |
240 | TIPC_MAX_SUBSCRIPTIONS); | 252 | TIPC_MAX_SUBSCRIPTIONS); |
241 | return -EINVAL; | 253 | return NULL; |
242 | } | 254 | } |
243 | 255 | ||
244 | /* Allocate subscription object */ | 256 | /* Allocate subscription object */ |
245 | sub = kmalloc(sizeof(*sub), GFP_ATOMIC); | 257 | sub = kmalloc(sizeof(*sub), GFP_ATOMIC); |
246 | if (!sub) { | 258 | if (!sub) { |
247 | pr_warn("Subscription rejected, no memory\n"); | 259 | pr_warn("Subscription rejected, no memory\n"); |
248 | return -ENOMEM; | 260 | return NULL; |
249 | } | 261 | } |
250 | 262 | ||
251 | /* Initialize subscription object */ | 263 | /* Initialize subscription object */ |
252 | sub->net = net; | 264 | sub->net = net; |
253 | sub->seq.type = htohl(s->seq.type, swap); | 265 | if (((filter & TIPC_SUB_PORTS) && (filter & TIPC_SUB_SERVICE)) || |
254 | sub->seq.lower = htohl(s->seq.lower, swap); | 266 | (htohl(s->seq.lower, swap) > htohl(s->seq.upper, swap))) { |
255 | sub->seq.upper = htohl(s->seq.upper, swap); | ||
256 | sub->timeout = msecs_to_jiffies(htohl(s->timeout, swap)); | ||
257 | sub->filter = htohl(s->filter, swap); | ||
258 | if ((!(sub->filter & TIPC_SUB_PORTS) == | ||
259 | !(sub->filter & TIPC_SUB_SERVICE)) || | ||
260 | (sub->seq.lower > sub->seq.upper)) { | ||
261 | pr_warn("Subscription rejected, illegal request\n"); | 267 | pr_warn("Subscription rejected, illegal request\n"); |
262 | kfree(sub); | 268 | kfree(sub); |
263 | return -EINVAL; | 269 | return NULL; |
264 | } | 270 | } |
265 | spin_lock_bh(&subscriber->lock); | 271 | |
266 | list_add(&sub->subscrp_list, &subscriber->subscrp_list); | ||
267 | spin_unlock_bh(&subscriber->lock); | ||
268 | sub->subscriber = subscriber; | ||
269 | sub->swap = swap; | 272 | sub->swap = swap; |
270 | memcpy(&sub->evt.s, s, sizeof(*s)); | 273 | memcpy(&sub->evt.s, s, sizeof(*s)); |
271 | atomic_inc(&tn->subscription_count); | 274 | atomic_inc(&tn->subscription_count); |
275 | return sub; | ||
276 | } | ||
277 | |||
278 | static void tipc_subscrp_subscribe(struct net *net, struct tipc_subscr *s, | ||
279 | struct tipc_subscriber *subscriber, int swap) | ||
280 | { | ||
281 | struct tipc_net *tn = net_generic(net, tipc_net_id); | ||
282 | struct tipc_subscription *sub = NULL; | ||
283 | u32 timeout; | ||
284 | |||
285 | sub = tipc_subscrp_create(net, s, swap); | ||
286 | if (!sub) | ||
287 | return tipc_conn_terminate(tn->topsrv, subscriber->conid); | ||
288 | |||
289 | spin_lock_bh(&subscriber->lock); | ||
290 | list_add(&sub->subscrp_list, &subscriber->subscrp_list); | ||
291 | tipc_subscrb_get(subscriber); | ||
292 | sub->subscriber = subscriber; | ||
293 | tipc_nametbl_subscribe(sub); | ||
294 | spin_unlock_bh(&subscriber->lock); | ||
295 | |||
296 | timeout = htohl(sub->evt.s.timeout, swap); | ||
297 | if (timeout == TIPC_WAIT_FOREVER) | ||
298 | return; | ||
299 | |||
272 | setup_timer(&sub->timer, tipc_subscrp_timeout, (unsigned long)sub); | 300 | setup_timer(&sub->timer, tipc_subscrp_timeout, (unsigned long)sub); |
273 | if (sub->timeout != TIPC_WAIT_FOREVER) | 301 | mod_timer(&sub->timer, jiffies + msecs_to_jiffies(timeout)); |
274 | sub->timeout += jiffies; | ||
275 | if (!mod_timer(&sub->timer, sub->timeout)) | ||
276 | tipc_subscrb_get(subscriber); | ||
277 | *sub_p = sub; | ||
278 | return 0; | ||
279 | } | 302 | } |
280 | 303 | ||
281 | /* Handle one termination request for the subscriber */ | 304 | /* Handle one termination request for the subscriber */ |
@@ -289,15 +312,22 @@ static void tipc_subscrb_rcv_cb(struct net *net, int conid, | |||
289 | struct sockaddr_tipc *addr, void *usr_data, | 312 | struct sockaddr_tipc *addr, void *usr_data, |
290 | void *buf, size_t len) | 313 | void *buf, size_t len) |
291 | { | 314 | { |
292 | struct tipc_subscriber *subscrb = usr_data; | 315 | struct tipc_subscriber *subscriber = usr_data; |
293 | struct tipc_subscription *sub = NULL; | 316 | struct tipc_subscr *s = (struct tipc_subscr *)buf; |
294 | struct tipc_net *tn = net_generic(net, tipc_net_id); | 317 | int swap; |
295 | 318 | ||
296 | if (tipc_subscrp_create(net, (struct tipc_subscr *)buf, subscrb, &sub)) | 319 | /* Determine subscriber's endianness */ |
297 | return tipc_conn_terminate(tn->topsrv, subscrb->conid); | 320 | swap = !(s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE | |
321 | TIPC_SUB_CANCEL)); | ||
322 | |||
323 | /* Detect & process a subscription cancellation request */ | ||
324 | if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) { | ||
325 | s->filter &= ~htohl(TIPC_SUB_CANCEL, swap); | ||
326 | return tipc_subscrp_cancel(s, subscriber); | ||
327 | } | ||
298 | 328 | ||
299 | if (sub) | 329 | if (s) |
300 | tipc_nametbl_subscribe(sub); | 330 | tipc_subscrp_subscribe(net, s, subscriber, swap); |
301 | } | 331 | } |
302 | 332 | ||
303 | /* Handle one request to establish a new subscriber */ | 333 | /* Handle one request to establish a new subscriber */ |