diff options
Diffstat (limited to 'net/llc/llc_conn.c')
-rw-r--r-- | net/llc/llc_conn.c | 93 |
1 files changed, 62 insertions, 31 deletions
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index c6bab39b018e..77bb3816655e 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c | |||
@@ -468,6 +468,19 @@ static int llc_exec_conn_trans_actions(struct sock *sk, | |||
468 | return rc; | 468 | return rc; |
469 | } | 469 | } |
470 | 470 | ||
471 | static inline bool llc_estab_match(const struct llc_sap *sap, | ||
472 | const struct llc_addr *daddr, | ||
473 | const struct llc_addr *laddr, | ||
474 | const struct sock *sk) | ||
475 | { | ||
476 | struct llc_sock *llc = llc_sk(sk); | ||
477 | |||
478 | return llc->laddr.lsap == laddr->lsap && | ||
479 | llc->daddr.lsap == daddr->lsap && | ||
480 | llc_mac_match(llc->laddr.mac, laddr->mac) && | ||
481 | llc_mac_match(llc->daddr.mac, daddr->mac); | ||
482 | } | ||
483 | |||
471 | /** | 484 | /** |
472 | * __llc_lookup_established - Finds connection for the remote/local sap/mac | 485 | * __llc_lookup_established - Finds connection for the remote/local sap/mac |
473 | * @sap: SAP | 486 | * @sap: SAP |
@@ -484,23 +497,26 @@ static struct sock *__llc_lookup_established(struct llc_sap *sap, | |||
484 | struct llc_addr *laddr) | 497 | struct llc_addr *laddr) |
485 | { | 498 | { |
486 | struct sock *rc; | 499 | struct sock *rc; |
487 | struct hlist_node *node; | 500 | struct hlist_nulls_node *node; |
488 | 501 | ||
489 | read_lock(&sap->sk_list.lock); | 502 | rcu_read_lock(); |
490 | sk_for_each(rc, node, &sap->sk_list.list) { | 503 | again: |
491 | struct llc_sock *llc = llc_sk(rc); | 504 | sk_nulls_for_each_rcu(rc, node, &sap->sk_list) { |
492 | 505 | if (llc_estab_match(sap, daddr, laddr, rc)) { | |
493 | if (llc->laddr.lsap == laddr->lsap && | 506 | /* Extra checks required by SLAB_DESTROY_BY_RCU */ |
494 | llc->daddr.lsap == daddr->lsap && | 507 | if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) |
495 | llc_mac_match(llc->laddr.mac, laddr->mac) && | 508 | goto again; |
496 | llc_mac_match(llc->daddr.mac, daddr->mac)) { | 509 | if (unlikely(llc_sk(rc)->sap != sap || |
497 | sock_hold(rc); | 510 | !llc_estab_match(sap, daddr, laddr, rc))) { |
511 | sock_put(rc); | ||
512 | continue; | ||
513 | } | ||
498 | goto found; | 514 | goto found; |
499 | } | 515 | } |
500 | } | 516 | } |
501 | rc = NULL; | 517 | rc = NULL; |
502 | found: | 518 | found: |
503 | read_unlock(&sap->sk_list.lock); | 519 | rcu_read_unlock(); |
504 | return rc; | 520 | return rc; |
505 | } | 521 | } |
506 | 522 | ||
@@ -516,6 +532,18 @@ struct sock *llc_lookup_established(struct llc_sap *sap, | |||
516 | return sk; | 532 | return sk; |
517 | } | 533 | } |
518 | 534 | ||
535 | static inline bool llc_listener_match(const struct llc_sap *sap, | ||
536 | const struct llc_addr *laddr, | ||
537 | const struct sock *sk) | ||
538 | { | ||
539 | struct llc_sock *llc = llc_sk(sk); | ||
540 | |||
541 | return sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN && | ||
542 | llc->laddr.lsap == laddr->lsap && | ||
543 | (llc_mac_match(llc->laddr.mac, laddr->mac) || | ||
544 | llc_mac_null(llc->laddr.mac)); | ||
545 | } | ||
546 | |||
519 | /** | 547 | /** |
520 | * llc_lookup_listener - Finds listener for local MAC + SAP | 548 | * llc_lookup_listener - Finds listener for local MAC + SAP |
521 | * @sap: SAP | 549 | * @sap: SAP |
@@ -530,23 +558,26 @@ static struct sock *llc_lookup_listener(struct llc_sap *sap, | |||
530 | struct llc_addr *laddr) | 558 | struct llc_addr *laddr) |
531 | { | 559 | { |
532 | struct sock *rc; | 560 | struct sock *rc; |
533 | struct hlist_node *node; | 561 | struct hlist_nulls_node *node; |
534 | 562 | ||
535 | read_lock(&sap->sk_list.lock); | 563 | rcu_read_lock(); |
536 | sk_for_each(rc, node, &sap->sk_list.list) { | 564 | again: |
537 | struct llc_sock *llc = llc_sk(rc); | 565 | sk_nulls_for_each_rcu(rc, node, &sap->sk_list) { |
538 | 566 | if (llc_listener_match(sap, laddr, rc)) { | |
539 | if (rc->sk_type == SOCK_STREAM && rc->sk_state == TCP_LISTEN && | 567 | /* Extra checks required by SLAB_DESTROY_BY_RCU */ |
540 | llc->laddr.lsap == laddr->lsap && | 568 | if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) |
541 | (llc_mac_match(llc->laddr.mac, laddr->mac) || | 569 | goto again; |
542 | llc_mac_null(llc->laddr.mac))) { | 570 | if (unlikely(llc_sk(rc)->sap != sap || |
543 | sock_hold(rc); | 571 | !llc_listener_match(sap, laddr, rc))) { |
572 | sock_put(rc); | ||
573 | continue; | ||
574 | } | ||
544 | goto found; | 575 | goto found; |
545 | } | 576 | } |
546 | } | 577 | } |
547 | rc = NULL; | 578 | rc = NULL; |
548 | found: | 579 | found: |
549 | read_unlock(&sap->sk_list.lock); | 580 | rcu_read_unlock(); |
550 | return rc; | 581 | return rc; |
551 | } | 582 | } |
552 | 583 | ||
@@ -652,10 +683,10 @@ static int llc_find_offset(int state, int ev_type) | |||
652 | void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) | 683 | void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) |
653 | { | 684 | { |
654 | llc_sap_hold(sap); | 685 | llc_sap_hold(sap); |
655 | write_lock_bh(&sap->sk_list.lock); | 686 | spin_lock_bh(&sap->sk_lock); |
656 | llc_sk(sk)->sap = sap; | 687 | llc_sk(sk)->sap = sap; |
657 | sk_add_node(sk, &sap->sk_list.list); | 688 | sk_nulls_add_node_rcu(sk, &sap->sk_list); |
658 | write_unlock_bh(&sap->sk_list.lock); | 689 | spin_unlock_bh(&sap->sk_lock); |
659 | } | 690 | } |
660 | 691 | ||
661 | /** | 692 | /** |
@@ -663,14 +694,14 @@ void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) | |||
663 | * @sap: SAP | 694 | * @sap: SAP |
664 | * @sk: socket | 695 | * @sk: socket |
665 | * | 696 | * |
666 | * This function removes a connection from sk_list.list of a SAP if | 697 | * This function removes a connection from sk_list of a SAP if |
667 | * the connection was in this list. | 698 | * the connection was in this list. |
668 | */ | 699 | */ |
669 | void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) | 700 | void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) |
670 | { | 701 | { |
671 | write_lock_bh(&sap->sk_list.lock); | 702 | spin_lock_bh(&sap->sk_lock); |
672 | sk_del_node_init(sk); | 703 | sk_nulls_del_node_init_rcu(sk); |
673 | write_unlock_bh(&sap->sk_list.lock); | 704 | spin_unlock_bh(&sap->sk_lock); |
674 | llc_sap_put(sap); | 705 | llc_sap_put(sap); |
675 | } | 706 | } |
676 | 707 | ||