diff options
Diffstat (limited to 'net/llc/llc_sap.c')
-rw-r--r-- | net/llc/llc_sap.c | 114 |
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 | ||
27 | static int llc_mac_header_len(unsigned short devtype) | 28 | static 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 | ||
301 | static 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 | 329 | again: | |
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; | ||
326 | found: | 351 | found: |
327 | read_unlock_bh(&sap->sk_list.lock); | 352 | rcu_read_unlock_bh(); |
328 | return rc; | 353 | return rc; |
329 | } | 354 | } |
330 | 355 | ||
356 | static 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 | |||
368 | static 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 | ||