aboutsummaryrefslogtreecommitdiffstats
path: root/net/llc/llc_sap.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/llc/llc_sap.c')
-rw-r--r--net/llc/llc_sap.c111
1 files changed, 82 insertions, 29 deletions
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index 008de1fc42ca..ad6e6e1cf22f 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -297,6 +297,17 @@ static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb,
297 llc_sap_state_process(sap, skb); 297 llc_sap_state_process(sap, skb);
298} 298}
299 299
300static inline bool llc_dgram_match(const struct llc_sap *sap,
301 const struct llc_addr *laddr,
302 const struct sock *sk)
303{
304 struct llc_sock *llc = llc_sk(sk);
305
306 return sk->sk_type == SOCK_DGRAM &&
307 llc->laddr.lsap == laddr->lsap &&
308 llc_mac_match(llc->laddr.mac, laddr->mac);
309}
310
300/** 311/**
301 * llc_lookup_dgram - Finds dgram socket for the local sap/mac 312 * llc_lookup_dgram - Finds dgram socket for the local sap/mac
302 * @sap: SAP 313 * @sap: SAP
@@ -309,25 +320,68 @@ static struct sock *llc_lookup_dgram(struct llc_sap *sap,
309 const struct llc_addr *laddr) 320 const struct llc_addr *laddr)
310{ 321{
311 struct sock *rc; 322 struct sock *rc;
312 struct hlist_node *node; 323 struct hlist_nulls_node *node;
313 324 int slot = llc_sk_laddr_hashfn(sap, laddr);
314 read_lock_bh(&sap->sk_list.lock); 325 struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot];
315 sk_for_each(rc, node, &sap->sk_list.list) { 326
316 struct llc_sock *llc = llc_sk(rc); 327 rcu_read_lock_bh();
317 328again:
318 if (rc->sk_type == SOCK_DGRAM && 329 sk_nulls_for_each_rcu(rc, node, laddr_hb) {
319 llc->laddr.lsap == laddr->lsap && 330 if (llc_dgram_match(sap, laddr, rc)) {
320 llc_mac_match(llc->laddr.mac, laddr->mac)) { 331 /* Extra checks required by SLAB_DESTROY_BY_RCU */
321 sock_hold(rc); 332 if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
333 goto again;
334 if (unlikely(llc_sk(rc)->sap != sap ||
335 !llc_dgram_match(sap, laddr, rc))) {
336 sock_put(rc);
337 continue;
338 }
322 goto found; 339 goto found;
323 } 340 }
324 } 341 }
325 rc = NULL; 342 rc = NULL;
343 /*
344 * if the nulls value we got at the end of this lookup is
345 * not the expected one, we must restart lookup.
346 * We probably met an item that was moved to another chain.
347 */
348 if (unlikely(get_nulls_value(node) != slot))
349 goto again;
326found: 350found:
327 read_unlock_bh(&sap->sk_list.lock); 351 rcu_read_unlock_bh();
328 return rc; 352 return rc;
329} 353}
330 354
355static inline bool llc_mcast_match(const struct llc_sap *sap,
356 const struct llc_addr *laddr,
357 const struct sk_buff *skb,
358 const struct sock *sk)
359{
360 struct llc_sock *llc = llc_sk(sk);
361
362 return sk->sk_type == SOCK_DGRAM &&
363 llc->laddr.lsap == laddr->lsap &&
364 llc->dev == skb->dev;
365}
366
367static void llc_do_mcast(struct llc_sap *sap, struct sk_buff *skb,
368 struct sock **stack, int count)
369{
370 struct sk_buff *skb1;
371 int i;
372
373 for (i = 0; i < count; i++) {
374 skb1 = skb_clone(skb, GFP_ATOMIC);
375 if (!skb1) {
376 sock_put(stack[i]);
377 continue;
378 }
379
380 llc_sap_rcv(sap, skb1, stack[i]);
381 sock_put(stack[i]);
382 }
383}
384
331/** 385/**
332 * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets. 386 * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets.
333 * @sap: SAP 387 * @sap: SAP
@@ -340,32 +394,31 @@ static void llc_sap_mcast(struct llc_sap *sap,
340 const struct llc_addr *laddr, 394 const struct llc_addr *laddr,
341 struct sk_buff *skb) 395 struct sk_buff *skb)
342{ 396{
343 struct sock *sk; 397 int i = 0, count = 256 / sizeof(struct sock *);
398 struct sock *sk, *stack[count];
344 struct hlist_node *node; 399 struct hlist_node *node;
400 struct llc_sock *llc;
401 struct hlist_head *dev_hb = llc_sk_dev_hash(sap, skb->dev->ifindex);
345 402
346 read_lock_bh(&sap->sk_list.lock); 403 spin_lock_bh(&sap->sk_lock);
347 sk_for_each(sk, node, &sap->sk_list.list) { 404 hlist_for_each_entry(llc, node, dev_hb, dev_hash_node) {
348 struct llc_sock *llc = llc_sk(sk);
349 struct sk_buff *skb1;
350 405
351 if (sk->sk_type != SOCK_DGRAM) 406 sk = &llc->sk;
352 continue;
353 407
354 if (llc->laddr.lsap != laddr->lsap) 408 if (!llc_mcast_match(sap, laddr, skb, sk))
355 continue; 409 continue;
356 410
357 if (llc->dev != skb->dev)
358 continue;
359
360 skb1 = skb_clone(skb, GFP_ATOMIC);
361 if (!skb1)
362 break;
363
364 sock_hold(sk); 411 sock_hold(sk);
365 llc_sap_rcv(sap, skb1, sk); 412 if (i < count)
366 sock_put(sk); 413 stack[i++] = sk;
414 else {
415 llc_do_mcast(sap, skb, stack, i);
416 i = 0;
417 }
367 } 418 }
368 read_unlock_bh(&sap->sk_list.lock); 419 spin_unlock_bh(&sap->sk_lock);
420
421 llc_do_mcast(sap, skb, stack, i);
369} 422}
370 423
371 424