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