forked from Minki/linux
[LLC]: Use refcounting with struct llc_sap
Signed-off-by: Jochen Friedrich <jochen@scram.de> Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
This commit is contained in:
parent
04e4223f44
commit
6e2144b768
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user