aboutsummaryrefslogtreecommitdiffstats
path: root/net/llc/llc_conn.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/llc/llc_conn.c')
-rw-r--r--net/llc/llc_conn.c70
1 files changed, 51 insertions, 19 deletions
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index 10cdfe2db830..a8dde9b010da 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -498,10 +498,12 @@ static struct sock *__llc_lookup_established(struct llc_sap *sap,
498{ 498{
499 struct sock *rc; 499 struct sock *rc;
500 struct hlist_nulls_node *node; 500 struct hlist_nulls_node *node;
501 int slot = llc_sk_laddr_hashfn(sap, laddr);
502 struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot];
501 503
502 rcu_read_lock(); 504 rcu_read_lock();
503again: 505again:
504 sk_nulls_for_each_rcu(rc, node, &sap->sk_list) { 506 sk_nulls_for_each_rcu(rc, node, laddr_hb) {
505 if (llc_estab_match(sap, daddr, laddr, rc)) { 507 if (llc_estab_match(sap, daddr, laddr, rc)) {
506 /* Extra checks required by SLAB_DESTROY_BY_RCU */ 508 /* Extra checks required by SLAB_DESTROY_BY_RCU */
507 if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) 509 if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
@@ -515,6 +517,13 @@ again:
515 } 517 }
516 } 518 }
517 rc = NULL; 519 rc = NULL;
520 /*
521 * if the nulls value we got at the end of this lookup is
522 * not the expected one, we must restart lookup.
523 * We probably met an item that was moved to another chain.
524 */
525 if (unlikely(get_nulls_value(node) != slot))
526 goto again;
518found: 527found:
519 rcu_read_unlock(); 528 rcu_read_unlock();
520 return rc; 529 return rc;
@@ -540,29 +549,20 @@ static inline bool llc_listener_match(const struct llc_sap *sap,
540 549
541 return sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN && 550 return sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN &&
542 llc->laddr.lsap == laddr->lsap && 551 llc->laddr.lsap == laddr->lsap &&
543 (llc_mac_match(llc->laddr.mac, laddr->mac) || 552 llc_mac_match(llc->laddr.mac, laddr->mac);
544 llc_mac_null(llc->laddr.mac));
545} 553}
546 554
547/** 555static struct sock *__llc_lookup_listener(struct llc_sap *sap,
548 * llc_lookup_listener - Finds listener for local MAC + SAP 556 struct llc_addr *laddr)
549 * @sap: SAP
550 * @laddr: address of local LLC (MAC + SAP)
551 *
552 * Search connection list of the SAP and finds connection listening on
553 * local mac, and local sap. Returns pointer for parent socket found,
554 * %NULL otherwise.
555 * Caller has to make sure local_bh is disabled.
556 */
557static struct sock *llc_lookup_listener(struct llc_sap *sap,
558 struct llc_addr *laddr)
559{ 557{
560 struct sock *rc; 558 struct sock *rc;
561 struct hlist_nulls_node *node; 559 struct hlist_nulls_node *node;
560 int slot = llc_sk_laddr_hashfn(sap, laddr);
561 struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot];
562 562
563 rcu_read_lock(); 563 rcu_read_lock();
564again: 564again:
565 sk_nulls_for_each_rcu(rc, node, &sap->sk_list) { 565 sk_nulls_for_each_rcu(rc, node, laddr_hb) {
566 if (llc_listener_match(sap, laddr, rc)) { 566 if (llc_listener_match(sap, laddr, rc)) {
567 /* Extra checks required by SLAB_DESTROY_BY_RCU */ 567 /* Extra checks required by SLAB_DESTROY_BY_RCU */
568 if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) 568 if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
@@ -576,11 +576,40 @@ again:
576 } 576 }
577 } 577 }
578 rc = NULL; 578 rc = NULL;
579 /*
580 * if the nulls value we got at the end of this lookup is
581 * not the expected one, we must restart lookup.
582 * We probably met an item that was moved to another chain.
583 */
584 if (unlikely(get_nulls_value(node) != slot))
585 goto again;
579found: 586found:
580 rcu_read_unlock(); 587 rcu_read_unlock();
581 return rc; 588 return rc;
582} 589}
583 590
591/**
592 * llc_lookup_listener - Finds listener for local MAC + SAP
593 * @sap: SAP
594 * @laddr: address of local LLC (MAC + SAP)
595 *
596 * Search connection list of the SAP and finds connection listening on
597 * local mac, and local sap. Returns pointer for parent socket found,
598 * %NULL otherwise.
599 * Caller has to make sure local_bh is disabled.
600 */
601static struct sock *llc_lookup_listener(struct llc_sap *sap,
602 struct llc_addr *laddr)
603{
604 static struct llc_addr null_addr;
605 struct sock *rc = __llc_lookup_listener(sap, laddr);
606
607 if (!rc)
608 rc = __llc_lookup_listener(sap, &null_addr);
609
610 return rc;
611}
612
584static struct sock *__llc_lookup(struct llc_sap *sap, 613static struct sock *__llc_lookup(struct llc_sap *sap,
585 struct llc_addr *daddr, 614 struct llc_addr *daddr,
586 struct llc_addr *laddr) 615 struct llc_addr *laddr)
@@ -678,18 +707,20 @@ static int llc_find_offset(int state, int ev_type)
678 * @sap: SAP 707 * @sap: SAP
679 * @sk: socket 708 * @sk: socket
680 * 709 *
681 * This function adds a socket to sk_list of a SAP. 710 * This function adds a socket to the hash tables of a SAP.
682 */ 711 */
683void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) 712void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
684{ 713{
685 struct llc_sock *llc = llc_sk(sk); 714 struct llc_sock *llc = llc_sk(sk);
686 struct hlist_head *dev_hb = llc_sk_dev_hash(sap, llc->dev->ifindex); 715 struct hlist_head *dev_hb = llc_sk_dev_hash(sap, llc->dev->ifindex);
716 struct hlist_nulls_head *laddr_hb = llc_sk_laddr_hash(sap, &llc->laddr);
687 717
688 llc_sap_hold(sap); 718 llc_sap_hold(sap);
689 llc_sk(sk)->sap = sap; 719 llc_sk(sk)->sap = sap;
690 720
691 spin_lock_bh(&sap->sk_lock); 721 spin_lock_bh(&sap->sk_lock);
692 sk_nulls_add_node_rcu(sk, &sap->sk_list); 722 sap->sk_count++;
723 sk_nulls_add_node_rcu(sk, laddr_hb);
693 hlist_add_head(&llc->dev_hash_node, dev_hb); 724 hlist_add_head(&llc->dev_hash_node, dev_hb);
694 spin_unlock_bh(&sap->sk_lock); 725 spin_unlock_bh(&sap->sk_lock);
695} 726}
@@ -699,7 +730,7 @@ void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
699 * @sap: SAP 730 * @sap: SAP
700 * @sk: socket 731 * @sk: socket
701 * 732 *
702 * This function removes a connection from sk_list of a SAP if 733 * This function removes a connection from the hash tables of a SAP if
703 * the connection was in this list. 734 * the connection was in this list.
704 */ 735 */
705void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) 736void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk)
@@ -709,6 +740,7 @@ void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk)
709 spin_lock_bh(&sap->sk_lock); 740 spin_lock_bh(&sap->sk_lock);
710 sk_nulls_del_node_init_rcu(sk); 741 sk_nulls_del_node_init_rcu(sk);
711 hlist_del(&llc->dev_hash_node); 742 hlist_del(&llc->dev_hash_node);
743 sap->sk_count--;
712 spin_unlock_bh(&sap->sk_lock); 744 spin_unlock_bh(&sap->sk_lock);
713 llc_sap_put(sap); 745 llc_sap_put(sap);
714} 746}