[LLC]: Use refcounting with struct llc_sap

Signed-off-by: default avatarJochen Friedrich <jochen@scram.de>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@mandriva.com>
parent 04e4223f
......@@ -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);
......
......@@ -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 */
......@@ -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);
}
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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);
}
/**
......@@ -730,32 +732,6 @@ drop:
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)
......
......@@ -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;
}
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment