diff options
Diffstat (limited to 'net/llc/llc_conn.c')
-rw-r--r-- | net/llc/llc_conn.c | 143 |
1 files changed, 107 insertions, 36 deletions
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index c6bab39b018e..a8dde9b010da 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,35 @@ 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 | int slot = llc_sk_laddr_hashfn(sap, laddr); | |
489 | read_lock(&sap->sk_list.lock); | 502 | struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot]; |
490 | sk_for_each(rc, node, &sap->sk_list.list) { | 503 | |
491 | struct llc_sock *llc = llc_sk(rc); | 504 | rcu_read_lock(); |
492 | 505 | again: | |
493 | if (llc->laddr.lsap == laddr->lsap && | 506 | sk_nulls_for_each_rcu(rc, node, laddr_hb) { |
494 | llc->daddr.lsap == daddr->lsap && | 507 | if (llc_estab_match(sap, daddr, laddr, rc)) { |
495 | llc_mac_match(llc->laddr.mac, laddr->mac) && | 508 | /* Extra checks required by SLAB_DESTROY_BY_RCU */ |
496 | llc_mac_match(llc->daddr.mac, daddr->mac)) { | 509 | if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) |
497 | sock_hold(rc); | 510 | goto again; |
511 | if (unlikely(llc_sk(rc)->sap != sap || | ||
512 | !llc_estab_match(sap, daddr, laddr, rc))) { | ||
513 | sock_put(rc); | ||
514 | continue; | ||
515 | } | ||
498 | goto found; | 516 | goto found; |
499 | } | 517 | } |
500 | } | 518 | } |
501 | 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; | ||
502 | found: | 527 | found: |
503 | read_unlock(&sap->sk_list.lock); | 528 | rcu_read_unlock(); |
504 | return rc; | 529 | return rc; |
505 | } | 530 | } |
506 | 531 | ||
@@ -516,6 +541,53 @@ struct sock *llc_lookup_established(struct llc_sap *sap, | |||
516 | return sk; | 541 | return sk; |
517 | } | 542 | } |
518 | 543 | ||
544 | static inline bool llc_listener_match(const struct llc_sap *sap, | ||
545 | const struct llc_addr *laddr, | ||
546 | const struct sock *sk) | ||
547 | { | ||
548 | struct llc_sock *llc = llc_sk(sk); | ||
549 | |||
550 | return sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN && | ||
551 | llc->laddr.lsap == laddr->lsap && | ||
552 | llc_mac_match(llc->laddr.mac, laddr->mac); | ||
553 | } | ||
554 | |||
555 | static struct sock *__llc_lookup_listener(struct llc_sap *sap, | ||
556 | struct llc_addr *laddr) | ||
557 | { | ||
558 | struct sock *rc; | ||
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 | |||
563 | rcu_read_lock(); | ||
564 | again: | ||
565 | sk_nulls_for_each_rcu(rc, node, laddr_hb) { | ||
566 | if (llc_listener_match(sap, laddr, rc)) { | ||
567 | /* Extra checks required by SLAB_DESTROY_BY_RCU */ | ||
568 | if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) | ||
569 | goto again; | ||
570 | if (unlikely(llc_sk(rc)->sap != sap || | ||
571 | !llc_listener_match(sap, laddr, rc))) { | ||
572 | sock_put(rc); | ||
573 | continue; | ||
574 | } | ||
575 | goto found; | ||
576 | } | ||
577 | } | ||
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; | ||
586 | found: | ||
587 | rcu_read_unlock(); | ||
588 | return rc; | ||
589 | } | ||
590 | |||
519 | /** | 591 | /** |
520 | * llc_lookup_listener - Finds listener for local MAC + SAP | 592 | * llc_lookup_listener - Finds listener for local MAC + SAP |
521 | * @sap: SAP | 593 | * @sap: SAP |
@@ -529,24 +601,12 @@ struct sock *llc_lookup_established(struct llc_sap *sap, | |||
529 | static struct sock *llc_lookup_listener(struct llc_sap *sap, | 601 | static struct sock *llc_lookup_listener(struct llc_sap *sap, |
530 | struct llc_addr *laddr) | 602 | struct llc_addr *laddr) |
531 | { | 603 | { |
532 | struct sock *rc; | 604 | static struct llc_addr null_addr; |
533 | struct hlist_node *node; | 605 | struct sock *rc = __llc_lookup_listener(sap, laddr); |
534 | 606 | ||
535 | read_lock(&sap->sk_list.lock); | 607 | if (!rc) |
536 | sk_for_each(rc, node, &sap->sk_list.list) { | 608 | rc = __llc_lookup_listener(sap, &null_addr); |
537 | struct llc_sock *llc = llc_sk(rc); | ||
538 | 609 | ||
539 | if (rc->sk_type == SOCK_STREAM && rc->sk_state == TCP_LISTEN && | ||
540 | llc->laddr.lsap == laddr->lsap && | ||
541 | (llc_mac_match(llc->laddr.mac, laddr->mac) || | ||
542 | llc_mac_null(llc->laddr.mac))) { | ||
543 | sock_hold(rc); | ||
544 | goto found; | ||
545 | } | ||
546 | } | ||
547 | rc = NULL; | ||
548 | found: | ||
549 | read_unlock(&sap->sk_list.lock); | ||
550 | return rc; | 610 | return rc; |
551 | } | 611 | } |
552 | 612 | ||
@@ -647,15 +707,22 @@ static int llc_find_offset(int state, int ev_type) | |||
647 | * @sap: SAP | 707 | * @sap: SAP |
648 | * @sk: socket | 708 | * @sk: socket |
649 | * | 709 | * |
650 | * This function adds a socket to sk_list of a SAP. | 710 | * This function adds a socket to the hash tables of a SAP. |
651 | */ | 711 | */ |
652 | void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) | 712 | void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) |
653 | { | 713 | { |
714 | struct llc_sock *llc = llc_sk(sk); | ||
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); | ||
717 | |||
654 | llc_sap_hold(sap); | 718 | llc_sap_hold(sap); |
655 | write_lock_bh(&sap->sk_list.lock); | ||
656 | llc_sk(sk)->sap = sap; | 719 | llc_sk(sk)->sap = sap; |
657 | sk_add_node(sk, &sap->sk_list.list); | 720 | |
658 | write_unlock_bh(&sap->sk_list.lock); | 721 | spin_lock_bh(&sap->sk_lock); |
722 | sap->sk_count++; | ||
723 | sk_nulls_add_node_rcu(sk, laddr_hb); | ||
724 | hlist_add_head(&llc->dev_hash_node, dev_hb); | ||
725 | spin_unlock_bh(&sap->sk_lock); | ||
659 | } | 726 | } |
660 | 727 | ||
661 | /** | 728 | /** |
@@ -663,14 +730,18 @@ void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) | |||
663 | * @sap: SAP | 730 | * @sap: SAP |
664 | * @sk: socket | 731 | * @sk: socket |
665 | * | 732 | * |
666 | * This function removes a connection from sk_list.list of a SAP if | 733 | * This function removes a connection from the hash tables of a SAP if |
667 | * the connection was in this list. | 734 | * the connection was in this list. |
668 | */ | 735 | */ |
669 | void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) | 736 | void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) |
670 | { | 737 | { |
671 | write_lock_bh(&sap->sk_list.lock); | 738 | struct llc_sock *llc = llc_sk(sk); |
672 | sk_del_node_init(sk); | 739 | |
673 | write_unlock_bh(&sap->sk_list.lock); | 740 | spin_lock_bh(&sap->sk_lock); |
741 | sk_nulls_del_node_init_rcu(sk); | ||
742 | hlist_del(&llc->dev_hash_node); | ||
743 | sap->sk_count--; | ||
744 | spin_unlock_bh(&sap->sk_lock); | ||
674 | llc_sap_put(sap); | 745 | llc_sap_put(sap); |
675 | } | 746 | } |
676 | 747 | ||