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.c93
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
471static 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) { 503again:
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;
502found: 518found:
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
535static 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) { 564again:
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;
548found: 579found:
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)
652void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) 683void 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 */
669void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) 700void 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