aboutsummaryrefslogtreecommitdiffstats
path: root/net/llc
diff options
context:
space:
mode:
Diffstat (limited to 'net/llc')
-rw-r--r--net/llc/af_llc.c64
-rw-r--r--net/llc/llc_conn.c143
-rw-r--r--net/llc/llc_core.c53
-rw-r--r--net/llc/llc_output.c45
-rw-r--r--net/llc/llc_proc.c69
-rw-r--r--net/llc/llc_sap.c111
6 files changed, 315 insertions, 170 deletions
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 3a66546cad0..e35d907fba2 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -47,6 +47,10 @@ static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout);
47#define dprintk(args...) 47#define dprintk(args...)
48#endif 48#endif
49 49
50/* Maybe we'll add some more in the future. */
51#define LLC_CMSG_PKTINFO 1
52
53
50/** 54/**
51 * llc_ui_next_link_no - return the next unused link number for a sap 55 * llc_ui_next_link_no - return the next unused link number for a sap
52 * @sap: Address of sap to get link number from. 56 * @sap: Address of sap to get link number from.
@@ -136,6 +140,7 @@ static struct proto llc_proto = {
136 .name = "LLC", 140 .name = "LLC",
137 .owner = THIS_MODULE, 141 .owner = THIS_MODULE,
138 .obj_size = sizeof(struct llc_sock), 142 .obj_size = sizeof(struct llc_sock),
143 .slab_flags = SLAB_DESTROY_BY_RCU,
139}; 144};
140 145
141/** 146/**
@@ -192,10 +197,8 @@ static int llc_ui_release(struct socket *sock)
192 llc->laddr.lsap, llc->daddr.lsap); 197 llc->laddr.lsap, llc->daddr.lsap);
193 if (!llc_send_disc(sk)) 198 if (!llc_send_disc(sk))
194 llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); 199 llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo);
195 if (!sock_flag(sk, SOCK_ZAPPED)) { 200 if (!sock_flag(sk, SOCK_ZAPPED))
196 llc_sap_put(llc->sap);
197 llc_sap_remove_socket(llc->sap, sk); 201 llc_sap_remove_socket(llc->sap, sk);
198 }
199 release_sock(sk); 202 release_sock(sk);
200 if (llc->dev) 203 if (llc->dev)
201 dev_put(llc->dev); 204 dev_put(llc->dev);
@@ -255,7 +258,14 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
255 if (!sock_flag(sk, SOCK_ZAPPED)) 258 if (!sock_flag(sk, SOCK_ZAPPED))
256 goto out; 259 goto out;
257 rc = -ENODEV; 260 rc = -ENODEV;
258 llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd); 261 if (sk->sk_bound_dev_if) {
262 llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if);
263 if (llc->dev && addr->sllc_arphrd != llc->dev->type) {
264 dev_put(llc->dev);
265 llc->dev = NULL;
266 }
267 } else
268 llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd);
259 if (!llc->dev) 269 if (!llc->dev)
260 goto out; 270 goto out;
261 rc = -EUSERS; 271 rc = -EUSERS;
@@ -306,7 +316,25 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
306 goto out; 316 goto out;
307 rc = -ENODEV; 317 rc = -ENODEV;
308 rtnl_lock(); 318 rtnl_lock();
309 llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd, addr->sllc_mac); 319 if (sk->sk_bound_dev_if) {
320 llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if);
321 if (llc->dev) {
322 if (!addr->sllc_arphrd)
323 addr->sllc_arphrd = llc->dev->type;
324 if (llc_mac_null(addr->sllc_mac))
325 memcpy(addr->sllc_mac, llc->dev->dev_addr,
326 IFHWADDRLEN);
327 if (addr->sllc_arphrd != llc->dev->type ||
328 !llc_mac_match(addr->sllc_mac,
329 llc->dev->dev_addr)) {
330 rc = -EINVAL;
331 dev_put(llc->dev);
332 llc->dev = NULL;
333 }
334 }
335 } else
336 llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd,
337 addr->sllc_mac);
310 rtnl_unlock(); 338 rtnl_unlock();
311 if (!llc->dev) 339 if (!llc->dev)
312 goto out; 340 goto out;
@@ -322,7 +350,6 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
322 rc = -EBUSY; /* some other network layer is using the sap */ 350 rc = -EBUSY; /* some other network layer is using the sap */
323 if (!sap) 351 if (!sap)
324 goto out; 352 goto out;
325 llc_sap_hold(sap);
326 } else { 353 } else {
327 struct llc_addr laddr, daddr; 354 struct llc_addr laddr, daddr;
328 struct sock *ask; 355 struct sock *ask;
@@ -591,6 +618,20 @@ static int llc_wait_data(struct sock *sk, long timeo)
591 return rc; 618 return rc;
592} 619}
593 620
621static void llc_cmsg_rcv(struct msghdr *msg, struct sk_buff *skb)
622{
623 struct llc_sock *llc = llc_sk(skb->sk);
624
625 if (llc->cmsg_flags & LLC_CMSG_PKTINFO) {
626 struct llc_pktinfo info;
627
628 info.lpi_ifindex = llc_sk(skb->sk)->dev->ifindex;
629 llc_pdu_decode_dsap(skb, &info.lpi_sap);
630 llc_pdu_decode_da(skb, info.lpi_mac);
631 put_cmsg(msg, SOL_LLC, LLC_OPT_PKTINFO, sizeof(info), &info);
632 }
633}
634
594/** 635/**
595 * llc_ui_accept - accept a new incoming connection. 636 * llc_ui_accept - accept a new incoming connection.
596 * @sock: Socket which connections arrive on. 637 * @sock: Socket which connections arrive on.
@@ -812,6 +853,8 @@ copy_uaddr:
812 memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); 853 memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr));
813 msg->msg_namelen = sizeof(*uaddr); 854 msg->msg_namelen = sizeof(*uaddr);
814 } 855 }
856 if (llc_sk(sk)->cmsg_flags)
857 llc_cmsg_rcv(msg, skb);
815 goto out; 858 goto out;
816} 859}
817 860
@@ -1030,6 +1073,12 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname,
1030 goto out; 1073 goto out;
1031 llc->rw = opt; 1074 llc->rw = opt;
1032 break; 1075 break;
1076 case LLC_OPT_PKTINFO:
1077 if (opt)
1078 llc->cmsg_flags |= LLC_CMSG_PKTINFO;
1079 else
1080 llc->cmsg_flags &= ~LLC_CMSG_PKTINFO;
1081 break;
1033 default: 1082 default:
1034 rc = -ENOPROTOOPT; 1083 rc = -ENOPROTOOPT;
1035 goto out; 1084 goto out;
@@ -1083,6 +1132,9 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname,
1083 val = llc->k; break; 1132 val = llc->k; break;
1084 case LLC_OPT_RX_WIN: 1133 case LLC_OPT_RX_WIN:
1085 val = llc->rw; break; 1134 val = llc->rw; break;
1135 case LLC_OPT_PKTINFO:
1136 val = (llc->cmsg_flags & LLC_CMSG_PKTINFO) != 0;
1137 break;
1086 default: 1138 default:
1087 rc = -ENOPROTOOPT; 1139 rc = -ENOPROTOOPT;
1088 goto out; 1140 goto out;
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index c6bab39b018..a8dde9b010d 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,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 505again:
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;
502found: 527found:
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
544static 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
555static 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();
564again:
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;
586found:
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,
529static struct sock *llc_lookup_listener(struct llc_sap *sap, 601static 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;
548found:
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 */
652void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) 712void 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 */
669void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) 736void 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
diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c
index ff4c0ab96a6..78167e81dfe 100644
--- a/net/llc/llc_core.c
+++ b/net/llc/llc_core.c
@@ -23,7 +23,7 @@
23#include <net/llc.h> 23#include <net/llc.h>
24 24
25LIST_HEAD(llc_sap_list); 25LIST_HEAD(llc_sap_list);
26DEFINE_RWLOCK(llc_sap_list_lock); 26DEFINE_SPINLOCK(llc_sap_list_lock);
27 27
28/** 28/**
29 * llc_sap_alloc - allocates and initializes sap. 29 * llc_sap_alloc - allocates and initializes sap.
@@ -33,40 +33,19 @@ DEFINE_RWLOCK(llc_sap_list_lock);
33static struct llc_sap *llc_sap_alloc(void) 33static struct llc_sap *llc_sap_alloc(void)
34{ 34{
35 struct llc_sap *sap = kzalloc(sizeof(*sap), GFP_ATOMIC); 35 struct llc_sap *sap = kzalloc(sizeof(*sap), GFP_ATOMIC);
36 int i;
36 37
37 if (sap) { 38 if (sap) {
38 /* sap->laddr.mac - leave as a null, it's filled by bind */ 39 /* sap->laddr.mac - leave as a null, it's filled by bind */
39 sap->state = LLC_SAP_STATE_ACTIVE; 40 sap->state = LLC_SAP_STATE_ACTIVE;
40 rwlock_init(&sap->sk_list.lock); 41 spin_lock_init(&sap->sk_lock);
42 for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++)
43 INIT_HLIST_NULLS_HEAD(&sap->sk_laddr_hash[i], i);
41 atomic_set(&sap->refcnt, 1); 44 atomic_set(&sap->refcnt, 1);
42 } 45 }
43 return sap; 46 return sap;
44} 47}
45 48
46/**
47 * llc_add_sap - add sap to station list
48 * @sap: Address of the sap
49 *
50 * Adds a sap to the LLC's station sap list.
51 */
52static void llc_add_sap(struct llc_sap *sap)
53{
54 list_add_tail(&sap->node, &llc_sap_list);
55}
56
57/**
58 * llc_del_sap - del sap from station list
59 * @sap: Address of the sap
60 *
61 * Removes a sap to the LLC's station sap list.
62 */
63static void llc_del_sap(struct llc_sap *sap)
64{
65 write_lock_bh(&llc_sap_list_lock);
66 list_del(&sap->node);
67 write_unlock_bh(&llc_sap_list_lock);
68}
69
70static struct llc_sap *__llc_sap_find(unsigned char sap_value) 49static struct llc_sap *__llc_sap_find(unsigned char sap_value)
71{ 50{
72 struct llc_sap* sap; 51 struct llc_sap* sap;
@@ -90,13 +69,13 @@ out:
90 */ 69 */
91struct llc_sap *llc_sap_find(unsigned char sap_value) 70struct llc_sap *llc_sap_find(unsigned char sap_value)
92{ 71{
93 struct llc_sap* sap; 72 struct llc_sap *sap;
94 73
95 read_lock_bh(&llc_sap_list_lock); 74 rcu_read_lock_bh();
96 sap = __llc_sap_find(sap_value); 75 sap = __llc_sap_find(sap_value);
97 if (sap) 76 if (sap)
98 llc_sap_hold(sap); 77 llc_sap_hold(sap);
99 read_unlock_bh(&llc_sap_list_lock); 78 rcu_read_unlock_bh();
100 return sap; 79 return sap;
101} 80}
102 81
@@ -117,7 +96,7 @@ struct llc_sap *llc_sap_open(unsigned char lsap,
117{ 96{
118 struct llc_sap *sap = NULL; 97 struct llc_sap *sap = NULL;
119 98
120 write_lock_bh(&llc_sap_list_lock); 99 spin_lock_bh(&llc_sap_list_lock);
121 if (__llc_sap_find(lsap)) /* SAP already exists */ 100 if (__llc_sap_find(lsap)) /* SAP already exists */
122 goto out; 101 goto out;
123 sap = llc_sap_alloc(); 102 sap = llc_sap_alloc();
@@ -125,9 +104,9 @@ struct llc_sap *llc_sap_open(unsigned char lsap,
125 goto out; 104 goto out;
126 sap->laddr.lsap = lsap; 105 sap->laddr.lsap = lsap;
127 sap->rcv_func = func; 106 sap->rcv_func = func;
128 llc_add_sap(sap); 107 list_add_tail_rcu(&sap->node, &llc_sap_list);
129out: 108out:
130 write_unlock_bh(&llc_sap_list_lock); 109 spin_unlock_bh(&llc_sap_list_lock);
131 return sap; 110 return sap;
132} 111}
133 112
@@ -142,8 +121,14 @@ out:
142 */ 121 */
143void llc_sap_close(struct llc_sap *sap) 122void llc_sap_close(struct llc_sap *sap)
144{ 123{
145 WARN_ON(!hlist_empty(&sap->sk_list.list)); 124 WARN_ON(sap->sk_count);
146 llc_del_sap(sap); 125
126 spin_lock_bh(&llc_sap_list_lock);
127 list_del_rcu(&sap->node);
128 spin_unlock_bh(&llc_sap_list_lock);
129
130 synchronize_rcu();
131
147 kfree(sap); 132 kfree(sap);
148} 133}
149 134
diff --git a/net/llc/llc_output.c b/net/llc/llc_output.c
index 754f4fedc85..b38a1079a98 100644
--- a/net/llc/llc_output.c
+++ b/net/llc/llc_output.c
@@ -33,48 +33,19 @@
33int llc_mac_hdr_init(struct sk_buff *skb, 33int llc_mac_hdr_init(struct sk_buff *skb,
34 const unsigned char *sa, const unsigned char *da) 34 const unsigned char *sa, const unsigned char *da)
35{ 35{
36 int rc = 0; 36 int rc = -EINVAL;
37 37
38 switch (skb->dev->type) { 38 switch (skb->dev->type) {
39#ifdef CONFIG_TR 39 case ARPHRD_IEEE802_TR:
40 case ARPHRD_IEEE802_TR: {
41 struct net_device *dev = skb->dev;
42 struct trh_hdr *trh;
43
44 skb_push(skb, sizeof(*trh));
45 skb_reset_mac_header(skb);
46 trh = tr_hdr(skb);
47 trh->ac = AC;
48 trh->fc = LLC_FRAME;
49 if (sa)
50 memcpy(trh->saddr, sa, dev->addr_len);
51 else
52 memset(trh->saddr, 0, dev->addr_len);
53 if (da) {
54 memcpy(trh->daddr, da, dev->addr_len);
55 tr_source_route(skb, trh, dev);
56 skb_reset_mac_header(skb);
57 }
58 break;
59 }
60#endif
61 case ARPHRD_ETHER: 40 case ARPHRD_ETHER:
62 case ARPHRD_LOOPBACK: { 41 case ARPHRD_LOOPBACK:
63 unsigned short len = skb->len; 42 rc = dev_hard_header(skb, skb->dev, ETH_P_802_2, da, sa,
64 struct ethhdr *eth; 43 skb->len);
65 44 if (rc > 0)
66 skb_push(skb, sizeof(*eth)); 45 rc = 0;
67 skb_reset_mac_header(skb);
68 eth = eth_hdr(skb);
69 eth->h_proto = htons(len);
70 memcpy(eth->h_dest, da, ETH_ALEN);
71 memcpy(eth->h_source, sa, ETH_ALEN);
72 break; 46 break;
73 }
74 default: 47 default:
75 printk(KERN_WARNING "device type not supported: %d\n", 48 WARN(1, "device type not supported: %d\n", skb->dev->type);
76 skb->dev->type);
77 rc = -EINVAL;
78 } 49 }
79 return rc; 50 return rc;
80} 51}
diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c
index be47ac427f6..7af1ff2d1f1 100644
--- a/net/llc/llc_proc.c
+++ b/net/llc/llc_proc.c
@@ -32,21 +32,23 @@ static void llc_ui_format_mac(struct seq_file *seq, u8 *addr)
32 32
33static struct sock *llc_get_sk_idx(loff_t pos) 33static struct sock *llc_get_sk_idx(loff_t pos)
34{ 34{
35 struct list_head *sap_entry;
36 struct llc_sap *sap; 35 struct llc_sap *sap;
37 struct hlist_node *node;
38 struct sock *sk = NULL; 36 struct sock *sk = NULL;
39 37 int i;
40 list_for_each(sap_entry, &llc_sap_list) { 38
41 sap = list_entry(sap_entry, struct llc_sap, node); 39 list_for_each_entry_rcu(sap, &llc_sap_list, node) {
42 40 spin_lock_bh(&sap->sk_lock);
43 read_lock_bh(&sap->sk_list.lock); 41 for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++) {
44 sk_for_each(sk, node, &sap->sk_list.list) { 42 struct hlist_nulls_head *head = &sap->sk_laddr_hash[i];
45 if (!pos) 43 struct hlist_nulls_node *node;
46 goto found; 44
47 --pos; 45 sk_nulls_for_each(sk, node, head) {
46 if (!pos)
47 goto found; /* keep the lock */
48 --pos;
49 }
48 } 50 }
49 read_unlock_bh(&sap->sk_list.lock); 51 spin_unlock_bh(&sap->sk_lock);
50 } 52 }
51 sk = NULL; 53 sk = NULL;
52found: 54found:
@@ -57,10 +59,23 @@ static void *llc_seq_start(struct seq_file *seq, loff_t *pos)
57{ 59{
58 loff_t l = *pos; 60 loff_t l = *pos;
59 61
60 read_lock_bh(&llc_sap_list_lock); 62 rcu_read_lock_bh();
61 return l ? llc_get_sk_idx(--l) : SEQ_START_TOKEN; 63 return l ? llc_get_sk_idx(--l) : SEQ_START_TOKEN;
62} 64}
63 65
66static struct sock *laddr_hash_next(struct llc_sap *sap, int bucket)
67{
68 struct hlist_nulls_node *node;
69 struct sock *sk = NULL;
70
71 while (++bucket < LLC_SK_LADDR_HASH_ENTRIES)
72 sk_nulls_for_each(sk, node, &sap->sk_laddr_hash[bucket])
73 goto out;
74
75out:
76 return sk;
77}
78
64static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos) 79static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
65{ 80{
66 struct sock* sk, *next; 81 struct sock* sk, *next;
@@ -73,25 +88,23 @@ static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
73 goto out; 88 goto out;
74 } 89 }
75 sk = v; 90 sk = v;
76 next = sk_next(sk); 91 next = sk_nulls_next(sk);
77 if (next) { 92 if (next) {
78 sk = next; 93 sk = next;
79 goto out; 94 goto out;
80 } 95 }
81 llc = llc_sk(sk); 96 llc = llc_sk(sk);
82 sap = llc->sap; 97 sap = llc->sap;
83 read_unlock_bh(&sap->sk_list.lock); 98 sk = laddr_hash_next(sap, llc_sk_laddr_hashfn(sap, &llc->laddr));
84 sk = NULL; 99 if (sk)
85 for (;;) { 100 goto out;
86 if (sap->node.next == &llc_sap_list) 101 spin_unlock_bh(&sap->sk_lock);
87 break; 102 list_for_each_entry_continue_rcu(sap, &llc_sap_list, node) {
88 sap = list_entry(sap->node.next, struct llc_sap, node); 103 spin_lock_bh(&sap->sk_lock);
89 read_lock_bh(&sap->sk_list.lock); 104 sk = laddr_hash_next(sap, -1);
90 if (!hlist_empty(&sap->sk_list.list)) { 105 if (sk)
91 sk = sk_head(&sap->sk_list.list); 106 break; /* keep the lock */
92 break; 107 spin_unlock_bh(&sap->sk_lock);
93 }
94 read_unlock_bh(&sap->sk_list.lock);
95 } 108 }
96out: 109out:
97 return sk; 110 return sk;
@@ -104,9 +117,9 @@ static void llc_seq_stop(struct seq_file *seq, void *v)
104 struct llc_sock *llc = llc_sk(sk); 117 struct llc_sock *llc = llc_sk(sk);
105 struct llc_sap *sap = llc->sap; 118 struct llc_sap *sap = llc->sap;
106 119
107 read_unlock_bh(&sap->sk_list.lock); 120 spin_unlock_bh(&sap->sk_lock);
108 } 121 }
109 read_unlock_bh(&llc_sap_list_lock); 122 rcu_read_unlock_bh();
110} 123}
111 124
112static int llc_seq_socket_show(struct seq_file *seq, void *v) 125static int llc_seq_socket_show(struct seq_file *seq, void *v)
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index 008de1fc42c..ad6e6e1cf22 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -297,6 +297,17 @@ static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb,
297 llc_sap_state_process(sap, skb); 297 llc_sap_state_process(sap, skb);
298} 298}
299 299
300static inline bool llc_dgram_match(const struct llc_sap *sap,
301 const struct llc_addr *laddr,
302 const struct sock *sk)
303{
304 struct llc_sock *llc = llc_sk(sk);
305
306 return sk->sk_type == SOCK_DGRAM &&
307 llc->laddr.lsap == laddr->lsap &&
308 llc_mac_match(llc->laddr.mac, laddr->mac);
309}
310
300/** 311/**
301 * llc_lookup_dgram - Finds dgram socket for the local sap/mac 312 * llc_lookup_dgram - Finds dgram socket for the local sap/mac
302 * @sap: SAP 313 * @sap: SAP
@@ -309,25 +320,68 @@ static struct sock *llc_lookup_dgram(struct llc_sap *sap,
309 const struct llc_addr *laddr) 320 const struct llc_addr *laddr)
310{ 321{
311 struct sock *rc; 322 struct sock *rc;
312 struct hlist_node *node; 323 struct hlist_nulls_node *node;
313 324 int slot = llc_sk_laddr_hashfn(sap, laddr);
314 read_lock_bh(&sap->sk_list.lock); 325 struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot];
315 sk_for_each(rc, node, &sap->sk_list.list) { 326
316 struct llc_sock *llc = llc_sk(rc); 327 rcu_read_lock_bh();
317 328again:
318 if (rc->sk_type == SOCK_DGRAM && 329 sk_nulls_for_each_rcu(rc, node, laddr_hb) {
319 llc->laddr.lsap == laddr->lsap && 330 if (llc_dgram_match(sap, laddr, rc)) {
320 llc_mac_match(llc->laddr.mac, laddr->mac)) { 331 /* Extra checks required by SLAB_DESTROY_BY_RCU */
321 sock_hold(rc); 332 if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
333 goto again;
334 if (unlikely(llc_sk(rc)->sap != sap ||
335 !llc_dgram_match(sap, laddr, rc))) {
336 sock_put(rc);
337 continue;
338 }
322 goto found; 339 goto found;
323 } 340 }
324 } 341 }
325 rc = NULL; 342 rc = NULL;
343 /*
344 * if the nulls value we got at the end of this lookup is
345 * not the expected one, we must restart lookup.
346 * We probably met an item that was moved to another chain.
347 */
348 if (unlikely(get_nulls_value(node) != slot))
349 goto again;
326found: 350found:
327 read_unlock_bh(&sap->sk_list.lock); 351 rcu_read_unlock_bh();
328 return rc; 352 return rc;
329} 353}
330 354
355static inline bool llc_mcast_match(const struct llc_sap *sap,
356 const struct llc_addr *laddr,
357 const struct sk_buff *skb,
358 const struct sock *sk)
359{
360 struct llc_sock *llc = llc_sk(sk);
361
362 return sk->sk_type == SOCK_DGRAM &&
363 llc->laddr.lsap == laddr->lsap &&
364 llc->dev == skb->dev;
365}
366
367static void llc_do_mcast(struct llc_sap *sap, struct sk_buff *skb,
368 struct sock **stack, int count)
369{
370 struct sk_buff *skb1;
371 int i;
372
373 for (i = 0; i < count; i++) {
374 skb1 = skb_clone(skb, GFP_ATOMIC);
375 if (!skb1) {
376 sock_put(stack[i]);
377 continue;
378 }
379
380 llc_sap_rcv(sap, skb1, stack[i]);
381 sock_put(stack[i]);
382 }
383}
384
331/** 385/**
332 * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets. 386 * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets.
333 * @sap: SAP 387 * @sap: SAP
@@ -340,32 +394,31 @@ static void llc_sap_mcast(struct llc_sap *sap,
340 const struct llc_addr *laddr, 394 const struct llc_addr *laddr,
341 struct sk_buff *skb) 395 struct sk_buff *skb)
342{ 396{
343 struct sock *sk; 397 int i = 0, count = 256 / sizeof(struct sock *);
398 struct sock *sk, *stack[count];
344 struct hlist_node *node; 399 struct hlist_node *node;
400 struct llc_sock *llc;
401 struct hlist_head *dev_hb = llc_sk_dev_hash(sap, skb->dev->ifindex);
345 402
346 read_lock_bh(&sap->sk_list.lock); 403 spin_lock_bh(&sap->sk_lock);
347 sk_for_each(sk, node, &sap->sk_list.list) { 404 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 405
351 if (sk->sk_type != SOCK_DGRAM) 406 sk = &llc->sk;
352 continue;
353 407
354 if (llc->laddr.lsap != laddr->lsap) 408 if (!llc_mcast_match(sap, laddr, skb, sk))
355 continue; 409 continue;
356 410
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); 411 sock_hold(sk);
365 llc_sap_rcv(sap, skb1, sk); 412 if (i < count)
366 sock_put(sk); 413 stack[i++] = sk;
414 else {
415 llc_do_mcast(sap, skb, stack, i);
416 i = 0;
417 }
367 } 418 }
368 read_unlock_bh(&sap->sk_list.lock); 419 spin_unlock_bh(&sap->sk_lock);
420
421 llc_do_mcast(sap, skb, stack, i);
369} 422}
370 423
371 424