aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/llc.h16
-rw-r--r--include/net/llc_conn.h1
-rw-r--r--net/802/p8022.c2
-rw-r--r--net/802/psnap.c2
-rw-r--r--net/llc/af_llc.c11
-rw-r--r--net/llc/llc_c_ac.c1
-rw-r--r--net/llc/llc_conn.c28
-rw-r--r--net/llc/llc_core.c34
-rw-r--r--net/llc/llc_input.c9
9 files changed, 56 insertions, 48 deletions
diff --git a/include/net/llc.h b/include/net/llc.h
index 8b8e2be289b1..93e5b443a9a7 100644
--- a/include/net/llc.h
+++ b/include/net/llc.h
@@ -17,6 +17,8 @@
17#include <linux/list.h> 17#include <linux/list.h>
18#include <linux/spinlock.h> 18#include <linux/spinlock.h>
19 19
20#include <asm/atomic.h>
21
20struct net_device; 22struct net_device;
21struct packet_type; 23struct packet_type;
22struct sk_buff; 24struct sk_buff;
@@ -44,6 +46,7 @@ struct llc_sap {
44 unsigned char state; 46 unsigned char state;
45 unsigned char p_bit; 47 unsigned char p_bit;
46 unsigned char f_bit; 48 unsigned char f_bit;
49 atomic_t refcnt;
47 int (*rcv_func)(struct sk_buff *skb, 50 int (*rcv_func)(struct sk_buff *skb,
48 struct net_device *dev, 51 struct net_device *dev,
49 struct packet_type *pt, 52 struct packet_type *pt,
@@ -81,7 +84,18 @@ extern struct llc_sap *llc_sap_open(unsigned char lsap,
81 struct net_device *dev, 84 struct net_device *dev,
82 struct packet_type *pt, 85 struct packet_type *pt,
83 struct net_device *orig_dev)); 86 struct net_device *orig_dev));
84extern void llc_sap_close(struct llc_sap *sap); 87static inline void llc_sap_hold(struct llc_sap *sap)
88{
89 atomic_inc(&sap->refcnt);
90}
91
92static inline void llc_sap_put(struct llc_sap *sap)
93{
94 extern void llc_sap_close(struct llc_sap *sap);
95
96 if (atomic_dec_and_test(&sap->refcnt))
97 llc_sap_close(sap);
98}
85 99
86extern struct llc_sap *llc_sap_find(unsigned char sap_value); 100extern struct llc_sap *llc_sap_find(unsigned char sap_value);
87 101
diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h
index 8a8ff4810135..b2889218c76a 100644
--- a/include/net/llc_conn.h
+++ b/include/net/llc_conn.h
@@ -115,5 +115,4 @@ extern void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk);
115 115
116extern u8 llc_data_accept_state(u8 state); 116extern u8 llc_data_accept_state(u8 state);
117extern void llc_build_offset_table(void); 117extern void llc_build_offset_table(void);
118extern int llc_release_sockets(struct llc_sap *sap);
119#endif /* LLC_CONN_H */ 118#endif /* LLC_CONN_H */
diff --git a/net/802/p8022.c b/net/802/p8022.c
index b24817c63ca8..2530f35241cd 100644
--- a/net/802/p8022.c
+++ b/net/802/p8022.c
@@ -56,7 +56,7 @@ struct datalink_proto *register_8022_client(unsigned char type,
56 56
57void unregister_8022_client(struct datalink_proto *proto) 57void unregister_8022_client(struct datalink_proto *proto)
58{ 58{
59 llc_sap_close(proto->sap); 59 llc_sap_put(proto->sap);
60 kfree(proto); 60 kfree(proto);
61} 61}
62 62
diff --git a/net/802/psnap.c b/net/802/psnap.c
index ab80b1fab53c..4d638944d933 100644
--- a/net/802/psnap.c
+++ b/net/802/psnap.c
@@ -106,7 +106,7 @@ module_init(snap_init);
106 106
107static void __exit snap_exit(void) 107static void __exit snap_exit(void)
108{ 108{
109 llc_sap_close(snap_sap); 109 llc_sap_put(snap_sap);
110} 110}
111 111
112module_exit(snap_exit); 112module_exit(snap_exit);
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index ad9aad807aa8..a75b8f2aab19 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -21,6 +21,7 @@
21 * See the GNU General Public License for more details. 21 * See the GNU General Public License for more details.
22 */ 22 */
23#include <linux/config.h> 23#include <linux/config.h>
24#include <linux/compiler.h>
24#include <linux/kernel.h> 25#include <linux/kernel.h>
25#include <linux/module.h> 26#include <linux/module.h>
26#include <linux/rtnetlink.h> 27#include <linux/rtnetlink.h>
@@ -188,10 +189,6 @@ static int llc_ui_release(struct socket *sock)
188 if (!sock_flag(sk, SOCK_ZAPPED)) 189 if (!sock_flag(sk, SOCK_ZAPPED))
189 llc_sap_remove_socket(llc->sap, sk); 190 llc_sap_remove_socket(llc->sap, sk);
190 release_sock(sk); 191 release_sock(sk);
191 if (llc->sap && hlist_empty(&llc->sap->sk_list.list)) {
192 llc_release_sockets(llc->sap);
193 llc_sap_close(llc->sap);
194 }
195 if (llc->dev) 192 if (llc->dev)
196 dev_put(llc->dev); 193 dev_put(llc->dev);
197 sock_put(sk); 194 sock_put(sk);
@@ -220,6 +217,7 @@ static int llc_ui_autoport(void)
220 llc_ui_sap_last_autoport = i + 2; 217 llc_ui_sap_last_autoport = i + 2;
221 goto out; 218 goto out;
222 } 219 }
220 llc_sap_put(sap);
223 } 221 }
224 llc_ui_sap_last_autoport = LLC_SAP_DYN_START; 222 llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
225 tries++; 223 tries++;
@@ -310,6 +308,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
310 rc = -EBUSY; /* some other network layer is using the sap */ 308 rc = -EBUSY; /* some other network layer is using the sap */
311 if (!sap) 309 if (!sap)
312 goto out; 310 goto out;
311 llc_sap_hold(sap);
313 } else { 312 } else {
314 struct llc_addr laddr, daddr; 313 struct llc_addr laddr, daddr;
315 struct sock *ask; 314 struct sock *ask;
@@ -326,7 +325,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
326 ask = llc_lookup_established(sap, &daddr, &laddr); 325 ask = llc_lookup_established(sap, &daddr, &laddr);
327 if (ask) { 326 if (ask) {
328 sock_put(ask); 327 sock_put(ask);
329 goto out; 328 goto out_put;
330 } 329 }
331 } 330 }
332 llc->laddr.lsap = addr->sllc_sap; 331 llc->laddr.lsap = addr->sllc_sap;
@@ -336,6 +335,8 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
336 llc_sap_add_socket(sap, sk); 335 llc_sap_add_socket(sap, sk);
337 sock_reset_flag(sk, SOCK_ZAPPED); 336 sock_reset_flag(sk, SOCK_ZAPPED);
338 rc = 0; 337 rc = 0;
338out_put:
339 llc_sap_put(sap);
339out: 340out:
340 return rc; 341 return rc;
341} 342}
diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c
index c1e75103189a..05236c2cbb9e 100644
--- a/net/llc/llc_c_ac.c
+++ b/net/llc/llc_c_ac.c
@@ -75,6 +75,7 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
75 llc->dev = skb->dev; 75 llc->dev = skb->dev;
76 ev->ind_prim = LLC_CONN_PRIM; 76 ev->ind_prim = LLC_CONN_PRIM;
77 rc = 0; 77 rc = 0;
78 llc_sap_put(sap);
78 } 79 }
79 return rc; 80 return rc;
80} 81}
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index 9f0e10e0978d..ab9e6d7e2875 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -633,6 +633,7 @@ static int llc_find_offset(int state, int ev_type)
633 */ 633 */
634void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) 634void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
635{ 635{
636 llc_sap_hold(sap);
636 write_lock_bh(&sap->sk_list.lock); 637 write_lock_bh(&sap->sk_list.lock);
637 llc_sk(sk)->sap = sap; 638 llc_sk(sk)->sap = sap;
638 sk_add_node(sk, &sap->sk_list.list); 639 sk_add_node(sk, &sap->sk_list.list);
@@ -652,6 +653,7 @@ void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk)
652 write_lock_bh(&sap->sk_list.lock); 653 write_lock_bh(&sap->sk_list.lock);
653 sk_del_node_init(sk); 654 sk_del_node_init(sk);
654 write_unlock_bh(&sap->sk_list.lock); 655 write_unlock_bh(&sap->sk_list.lock);
656 llc_sap_put(sap);
655} 657}
656 658
657/** 659/**
@@ -731,32 +733,6 @@ static atomic_t llc_sock_nr;
731#endif 733#endif
732 734
733/** 735/**
734 * llc_release_sockets - releases all sockets in a sap
735 * @sap: sap to release its sockets
736 *
737 * Releases all connections of a sap. Returns 0 if all actions complete
738 * successfully, nonzero otherwise
739 */
740int llc_release_sockets(struct llc_sap *sap)
741{
742 int rc = 0;
743 struct sock *sk;
744 struct hlist_node *node;
745
746 write_lock_bh(&sap->sk_list.lock);
747
748 sk_for_each(sk, node, &sap->sk_list.list) {
749 llc_sk(sk)->state = LLC_CONN_STATE_TEMP;
750
751 if (llc_send_disc(sk))
752 rc = 1;
753 }
754
755 write_unlock_bh(&sap->sk_list.lock);
756 return rc;
757}
758
759/**
760 * llc_backlog_rcv - Processes rx frames and expired timers. 736 * llc_backlog_rcv - Processes rx frames and expired timers.
761 * @sk: LLC sock (p8022 connection) 737 * @sk: LLC sock (p8022 connection)
762 * @skb: queued rx frame or event 738 * @skb: queued rx frame or event
diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c
index 9727455bf0e7..9ccff1266b26 100644
--- a/net/llc/llc_core.c
+++ b/net/llc/llc_core.c
@@ -40,6 +40,7 @@ static struct llc_sap *llc_sap_alloc(void)
40 sap->state = LLC_SAP_STATE_ACTIVE; 40 sap->state = LLC_SAP_STATE_ACTIVE;
41 memcpy(sap->laddr.mac, llc_station_mac_sa, ETH_ALEN); 41 memcpy(sap->laddr.mac, llc_station_mac_sa, ETH_ALEN);
42 rwlock_init(&sap->sk_list.lock); 42 rwlock_init(&sap->sk_list.lock);
43 atomic_set(&sap->refcnt, 1);
43 } 44 }
44 return sap; 45 return sap;
45} 46}
@@ -52,9 +53,7 @@ static struct llc_sap *llc_sap_alloc(void)
52 */ 53 */
53static void llc_add_sap(struct llc_sap *sap) 54static void llc_add_sap(struct llc_sap *sap)
54{ 55{
55 write_lock_bh(&llc_sap_list_lock);
56 list_add_tail(&sap->node, &llc_sap_list); 56 list_add_tail(&sap->node, &llc_sap_list);
57 write_unlock_bh(&llc_sap_list_lock);
58} 57}
59 58
60/** 59/**
@@ -70,11 +69,25 @@ static void llc_del_sap(struct llc_sap *sap)
70 write_unlock_bh(&llc_sap_list_lock); 69 write_unlock_bh(&llc_sap_list_lock);
71} 70}
72 71
72struct llc_sap *__llc_sap_find(unsigned char sap_value)
73{
74 struct llc_sap* sap;
75
76 list_for_each_entry(sap, &llc_sap_list, node)
77 if (sap->laddr.lsap == sap_value)
78 goto out;
79 sap = NULL;
80out:
81 return sap;
82}
83
73/** 84/**
74 * llc_sap_find - searchs a SAP in station 85 * llc_sap_find - searchs a SAP in station
75 * @sap_value: sap to be found 86 * @sap_value: sap to be found
76 * 87 *
77 * Searchs for a sap in the sap list of the LLC's station upon the sap ID. 88 * Searchs for a sap in the sap list of the LLC's station upon the sap ID.
89 * If the sap is found it will be refcounted and the user will have to do
90 * a llc_sap_put after use.
78 * Returns the sap or %NULL if not found. 91 * Returns the sap or %NULL if not found.
79 */ 92 */
80struct llc_sap *llc_sap_find(unsigned char sap_value) 93struct llc_sap *llc_sap_find(unsigned char sap_value)
@@ -82,11 +95,9 @@ struct llc_sap *llc_sap_find(unsigned char sap_value)
82 struct llc_sap* sap; 95 struct llc_sap* sap;
83 96
84 read_lock_bh(&llc_sap_list_lock); 97 read_lock_bh(&llc_sap_list_lock);
85 list_for_each_entry(sap, &llc_sap_list, node) 98 sap = __llc_sap_find(sap_value);
86 if (sap->laddr.lsap == sap_value) 99 if (sap)
87 goto out; 100 llc_sap_hold(sap);
88 sap = NULL;
89out:
90 read_unlock_bh(&llc_sap_list_lock); 101 read_unlock_bh(&llc_sap_list_lock);
91 return sap; 102 return sap;
92} 103}
@@ -106,19 +117,20 @@ struct llc_sap *llc_sap_open(unsigned char lsap,
106 struct packet_type *pt, 117 struct packet_type *pt,
107 struct net_device *orig_dev)) 118 struct net_device *orig_dev))
108{ 119{
109 struct llc_sap *sap = llc_sap_find(lsap); 120 struct llc_sap *sap = NULL;
110 121
111 if (sap) { /* SAP already exists */ 122 write_lock_bh(&llc_sap_list_lock);
112 sap = NULL; 123 if (__llc_sap_find(lsap)) /* SAP already exists */
113 goto out; 124 goto out;
114 }
115 sap = llc_sap_alloc(); 125 sap = llc_sap_alloc();
116 if (!sap) 126 if (!sap)
117 goto out; 127 goto out;
118 sap->laddr.lsap = lsap; 128 sap->laddr.lsap = lsap;
119 sap->rcv_func = func; 129 sap->rcv_func = func;
130 llc_sap_hold(sap);
120 llc_add_sap(sap); 131 llc_add_sap(sap);
121out: 132out:
133 write_unlock_bh(&llc_sap_list_lock);
122 return sap; 134 return sap;
123} 135}
124 136
diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c
index 60c1acac7c97..789eec426451 100644
--- a/net/llc/llc_input.c
+++ b/net/llc/llc_input.c
@@ -166,17 +166,22 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
166 */ 166 */
167 if (sap->rcv_func) { 167 if (sap->rcv_func) {
168 sap->rcv_func(skb, dev, pt, orig_dev); 168 sap->rcv_func(skb, dev, pt, orig_dev);
169 goto out; 169 goto out_put;
170 } 170 }
171 dest = llc_pdu_type(skb); 171 dest = llc_pdu_type(skb);
172 if (unlikely(!dest || !llc_type_handlers[dest - 1])) 172 if (unlikely(!dest || !llc_type_handlers[dest - 1]))
173 goto drop; 173 goto drop_put;
174 llc_type_handlers[dest - 1](sap, skb); 174 llc_type_handlers[dest - 1](sap, skb);
175out_put:
176 llc_sap_put(sap);
175out: 177out:
176 return 0; 178 return 0;
177drop: 179drop:
178 kfree_skb(skb); 180 kfree_skb(skb);
179 goto out; 181 goto out;
182drop_put:
183 kfree_skb(skb);
184 goto out_put;
180handle_station: 185handle_station:
181 if (!llc_station_handler) 186 if (!llc_station_handler)
182 goto drop; 187 goto drop;