diff options
-rw-r--r-- | include/net/llc.h | 16 | ||||
-rw-r--r-- | include/net/llc_conn.h | 1 | ||||
-rw-r--r-- | net/802/p8022.c | 2 | ||||
-rw-r--r-- | net/802/psnap.c | 2 | ||||
-rw-r--r-- | net/llc/af_llc.c | 11 | ||||
-rw-r--r-- | net/llc/llc_c_ac.c | 1 | ||||
-rw-r--r-- | net/llc/llc_conn.c | 28 | ||||
-rw-r--r-- | net/llc/llc_core.c | 34 | ||||
-rw-r--r-- | net/llc/llc_input.c | 9 |
9 files changed, 56 insertions, 48 deletions
diff --git a/include/net/llc.h b/include/net/llc.h index 8b8e2be..93e5b44 100644 --- a/include/net/llc.h +++ b/include/net/llc.h @@ -17,6 +17,8 @@ #include <linux/list.h> #include <linux/spinlock.h> +#include <asm/atomic.h> + struct net_device; struct packet_type; struct sk_buff; @@ -44,6 +46,7 @@ struct llc_sap { unsigned char state; unsigned char p_bit; unsigned char f_bit; + atomic_t refcnt; int (*rcv_func)(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, @@ -81,7 +84,18 @@ extern struct llc_sap *llc_sap_open(unsigned char lsap, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)); -extern void llc_sap_close(struct llc_sap *sap); +static inline void llc_sap_hold(struct llc_sap *sap) +{ + atomic_inc(&sap->refcnt); +} + +static inline void llc_sap_put(struct llc_sap *sap) +{ + extern void llc_sap_close(struct llc_sap *sap); + + if (atomic_dec_and_test(&sap->refcnt)) + llc_sap_close(sap); +} extern struct llc_sap *llc_sap_find(unsigned char sap_value); diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h index 8a8ff48..b288921 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); extern u8 llc_data_accept_state(u8 state); extern void llc_build_offset_table(void); -extern int llc_release_sockets(struct llc_sap *sap); #endif /* LLC_CONN_H */ diff --git a/net/802/p8022.c b/net/802/p8022.c index b24817c..2530f35 100644 --- a/net/802/p8022.c +++ b/net/802/p8022.c @@ -56,7 +56,7 @@ struct datalink_proto *register_8022_client(unsigned char type, void unregister_8022_client(struct datalink_proto *proto) { - llc_sap_close(proto->sap); + llc_sap_put(proto->sap); kfree(proto); } diff --git a/net/802/psnap.c b/net/802/psnap.c index ab80b1f..4d63894 100644 --- a/net/802/psnap.c +++ b/net/802/psnap.c @@ -106,7 +106,7 @@ module_init(snap_init); static void __exit snap_exit(void) { - llc_sap_close(snap_sap); + llc_sap_put(snap_sap); } module_exit(snap_exit); diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index ad9aad8..a75b8f2 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -21,6 +21,7 @@ * See the GNU General Public License for more details. */ #include <linux/config.h> +#include <linux/compiler.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/rtnetlink.h> @@ -188,10 +189,6 @@ static int llc_ui_release(struct socket *sock) if (!sock_flag(sk, SOCK_ZAPPED)) llc_sap_remove_socket(llc->sap, sk); release_sock(sk); - if (llc->sap && hlist_empty(&llc->sap->sk_list.list)) { - llc_release_sockets(llc->sap); - llc_sap_close(llc->sap); - } if (llc->dev) dev_put(llc->dev); sock_put(sk); @@ -220,6 +217,7 @@ static int llc_ui_autoport(void) llc_ui_sap_last_autoport = i + 2; goto out; } + llc_sap_put(sap); } llc_ui_sap_last_autoport = LLC_SAP_DYN_START; tries++; @@ -310,6 +308,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) rc = -EBUSY; /* some other network layer is using the sap */ if (!sap) goto out; + llc_sap_hold(sap); } else { struct llc_addr laddr, daddr; struct sock *ask; @@ -326,7 +325,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) ask = llc_lookup_established(sap, &daddr, &laddr); if (ask) { sock_put(ask); - goto out; + goto out_put; } } llc->laddr.lsap = addr->sllc_sap; @@ -336,6 +335,8 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) llc_sap_add_socket(sap, sk); sock_reset_flag(sk, SOCK_ZAPPED); rc = 0; +out_put: + llc_sap_put(sap); out: return rc; } diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c index c1e7510..05236c2 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) llc->dev = skb->dev; ev->ind_prim = LLC_CONN_PRIM; rc = 0; + llc_sap_put(sap); } return rc; } diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 9f0e10e..ab9e6d7 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) */ void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) { + llc_sap_hold(sap); write_lock_bh(&sap->sk_list.lock); llc_sk(sk)->sap = sap; sk_add_node(sk, &sap->sk_list.list); @@ -652,6 +653,7 @@ void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) write_lock_bh(&sap->sk_list.lock); sk_del_node_init(sk); write_unlock_bh(&sap->sk_list.lock); + llc_sap_put(sap); } /** @@ -731,32 +733,6 @@ static atomic_t llc_sock_nr; #endif /** - * llc_release_sockets - releases all sockets in a sap - * @sap: sap to release its sockets - * - * Releases all connections of a sap. Returns 0 if all actions complete - * successfully, nonzero otherwise - */ -int llc_release_sockets(struct llc_sap *sap) -{ - int rc = 0; - struct sock *sk; - struct hlist_node *node; - - write_lock_bh(&sap->sk_list.lock); - - sk_for_each(sk, node, &sap->sk_list.list) { - llc_sk(sk)->state = LLC_CONN_STATE_TEMP; - - if (llc_send_disc(sk)) - rc = 1; - } - - write_unlock_bh(&sap->sk_list.lock); - return rc; -} - -/** * llc_backlog_rcv - Processes rx frames and expired timers. * @sk: LLC sock (p8022 connection) * @skb: queued rx frame or event diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c index 9727455..9ccff12 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) sap->state = LLC_SAP_STATE_ACTIVE; memcpy(sap->laddr.mac, llc_station_mac_sa, ETH_ALEN); rwlock_init(&sap->sk_list.lock); + atomic_set(&sap->refcnt, 1); } return sap; } @@ -52,9 +53,7 @@ static struct llc_sap *llc_sap_alloc(void) */ static void llc_add_sap(struct llc_sap *sap) { - write_lock_bh(&llc_sap_list_lock); list_add_tail(&sap->node, &llc_sap_list); - write_unlock_bh(&llc_sap_list_lock); } /** @@ -70,11 +69,25 @@ static void llc_del_sap(struct llc_sap *sap) write_unlock_bh(&llc_sap_list_lock); } +struct llc_sap *__llc_sap_find(unsigned char sap_value) +{ + struct llc_sap* sap; + + list_for_each_entry(sap, &llc_sap_list, node) + if (sap->laddr.lsap == sap_value) + goto out; + sap = NULL; +out: + return sap; +} + /** * llc_sap_find - searchs a SAP in station * @sap_value: sap to be found * * Searchs for a sap in the sap list of the LLC's station upon the sap ID. + * If the sap is found it will be refcounted and the user will have to do + * a llc_sap_put after use. * Returns the sap or %NULL if not found. */ struct llc_sap *llc_sap_find(unsigned char sap_value) @@ -82,11 +95,9 @@ struct llc_sap *llc_sap_find(unsigned char sap_value) struct llc_sap* sap; read_lock_bh(&llc_sap_list_lock); - list_for_each_entry(sap, &llc_sap_list, node) - if (sap->laddr.lsap == sap_value) - goto out; - sap = NULL; -out: + sap = __llc_sap_find(sap_value); + if (sap) + llc_sap_hold(sap); read_unlock_bh(&llc_sap_list_lock); return sap; } @@ -106,19 +117,20 @@ struct llc_sap *llc_sap_open(unsigned char lsap, struct packet_type *pt, struct net_device *orig_dev)) { - struct llc_sap *sap = llc_sap_find(lsap); + struct llc_sap *sap = NULL; - if (sap) { /* SAP already exists */ - sap = NULL; + write_lock_bh(&llc_sap_list_lock); + if (__llc_sap_find(lsap)) /* SAP already exists */ goto out; - } sap = llc_sap_alloc(); if (!sap) goto out; sap->laddr.lsap = lsap; sap->rcv_func = func; + llc_sap_hold(sap); llc_add_sap(sap); out: + write_unlock_bh(&llc_sap_list_lock); return sap; } diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c index 60c1aca..789eec4 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, */ if (sap->rcv_func) { sap->rcv_func(skb, dev, pt, orig_dev); - goto out; + goto out_put; } dest = llc_pdu_type(skb); if (unlikely(!dest || !llc_type_handlers[dest - 1])) - goto drop; + goto drop_put; llc_type_handlers[dest - 1](sap, skb); +out_put: + llc_sap_put(sap); out: return 0; drop: kfree_skb(skb); goto out; +drop_put: + kfree_skb(skb); + goto out_put; handle_station: if (!llc_station_handler) goto drop; |