mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-07 13:43:51 +00:00
[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/list.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
|
#include <asm/atomic.h>
|
||||||
|
|
||||||
struct net_device;
|
struct net_device;
|
||||||
struct packet_type;
|
struct packet_type;
|
||||||
struct sk_buff;
|
struct sk_buff;
|
||||||
@ -44,6 +46,7 @@ struct llc_sap {
|
|||||||
unsigned char state;
|
unsigned char state;
|
||||||
unsigned char p_bit;
|
unsigned char p_bit;
|
||||||
unsigned char f_bit;
|
unsigned char f_bit;
|
||||||
|
atomic_t refcnt;
|
||||||
int (*rcv_func)(struct sk_buff *skb,
|
int (*rcv_func)(struct sk_buff *skb,
|
||||||
struct net_device *dev,
|
struct net_device *dev,
|
||||||
struct packet_type *pt,
|
struct packet_type *pt,
|
||||||
@ -81,7 +84,18 @@ extern struct llc_sap *llc_sap_open(unsigned char lsap,
|
|||||||
struct net_device *dev,
|
struct net_device *dev,
|
||||||
struct packet_type *pt,
|
struct packet_type *pt,
|
||||||
struct net_device *orig_dev));
|
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);
|
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 u8 llc_data_accept_state(u8 state);
|
||||||
extern void llc_build_offset_table(void);
|
extern void llc_build_offset_table(void);
|
||||||
extern int llc_release_sockets(struct llc_sap *sap);
|
|
||||||
#endif /* LLC_CONN_H */
|
#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)
|
void unregister_8022_client(struct datalink_proto *proto)
|
||||||
{
|
{
|
||||||
llc_sap_close(proto->sap);
|
llc_sap_put(proto->sap);
|
||||||
kfree(proto);
|
kfree(proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ module_init(snap_init);
|
|||||||
|
|
||||||
static void __exit snap_exit(void)
|
static void __exit snap_exit(void)
|
||||||
{
|
{
|
||||||
llc_sap_close(snap_sap);
|
llc_sap_put(snap_sap);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_exit(snap_exit);
|
module_exit(snap_exit);
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
* See the GNU General Public License for more details.
|
* See the GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
|
#include <linux/compiler.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
@ -188,10 +189,6 @@ static int llc_ui_release(struct socket *sock)
|
|||||||
if (!sock_flag(sk, SOCK_ZAPPED))
|
if (!sock_flag(sk, SOCK_ZAPPED))
|
||||||
llc_sap_remove_socket(llc->sap, sk);
|
llc_sap_remove_socket(llc->sap, sk);
|
||||||
release_sock(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)
|
if (llc->dev)
|
||||||
dev_put(llc->dev);
|
dev_put(llc->dev);
|
||||||
sock_put(sk);
|
sock_put(sk);
|
||||||
@ -220,6 +217,7 @@ static int llc_ui_autoport(void)
|
|||||||
llc_ui_sap_last_autoport = i + 2;
|
llc_ui_sap_last_autoport = i + 2;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
llc_sap_put(sap);
|
||||||
}
|
}
|
||||||
llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
|
llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
|
||||||
tries++;
|
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 */
|
rc = -EBUSY; /* some other network layer is using the sap */
|
||||||
if (!sap)
|
if (!sap)
|
||||||
goto out;
|
goto out;
|
||||||
|
llc_sap_hold(sap);
|
||||||
} else {
|
} else {
|
||||||
struct llc_addr laddr, daddr;
|
struct llc_addr laddr, daddr;
|
||||||
struct sock *ask;
|
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);
|
ask = llc_lookup_established(sap, &daddr, &laddr);
|
||||||
if (ask) {
|
if (ask) {
|
||||||
sock_put(ask);
|
sock_put(ask);
|
||||||
goto out;
|
goto out_put;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
llc->laddr.lsap = addr->sllc_sap;
|
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);
|
llc_sap_add_socket(sap, sk);
|
||||||
sock_reset_flag(sk, SOCK_ZAPPED);
|
sock_reset_flag(sk, SOCK_ZAPPED);
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
out_put:
|
||||||
|
llc_sap_put(sap);
|
||||||
out:
|
out:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,7 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
|
|||||||
llc->dev = skb->dev;
|
llc->dev = skb->dev;
|
||||||
ev->ind_prim = LLC_CONN_PRIM;
|
ev->ind_prim = LLC_CONN_PRIM;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
llc_sap_put(sap);
|
||||||
}
|
}
|
||||||
return rc;
|
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)
|
void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
|
||||||
{
|
{
|
||||||
|
llc_sap_hold(sap);
|
||||||
write_lock_bh(&sap->sk_list.lock);
|
write_lock_bh(&sap->sk_list.lock);
|
||||||
llc_sk(sk)->sap = sap;
|
llc_sk(sk)->sap = sap;
|
||||||
sk_add_node(sk, &sap->sk_list.list);
|
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);
|
write_lock_bh(&sap->sk_list.lock);
|
||||||
sk_del_node_init(sk);
|
sk_del_node_init(sk);
|
||||||
write_unlock_bh(&sap->sk_list.lock);
|
write_unlock_bh(&sap->sk_list.lock);
|
||||||
|
llc_sap_put(sap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -730,32 +732,6 @@ void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb)
|
|||||||
static atomic_t llc_sock_nr;
|
static atomic_t llc_sock_nr;
|
||||||
#endif
|
#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.
|
* llc_backlog_rcv - Processes rx frames and expired timers.
|
||||||
* @sk: LLC sock (p8022 connection)
|
* @sk: LLC sock (p8022 connection)
|
||||||
|
@ -40,6 +40,7 @@ static struct llc_sap *llc_sap_alloc(void)
|
|||||||
sap->state = LLC_SAP_STATE_ACTIVE;
|
sap->state = LLC_SAP_STATE_ACTIVE;
|
||||||
memcpy(sap->laddr.mac, llc_station_mac_sa, ETH_ALEN);
|
memcpy(sap->laddr.mac, llc_station_mac_sa, ETH_ALEN);
|
||||||
rwlock_init(&sap->sk_list.lock);
|
rwlock_init(&sap->sk_list.lock);
|
||||||
|
atomic_set(&sap->refcnt, 1);
|
||||||
}
|
}
|
||||||
return sap;
|
return sap;
|
||||||
}
|
}
|
||||||
@ -52,9 +53,7 @@ static struct llc_sap *llc_sap_alloc(void)
|
|||||||
*/
|
*/
|
||||||
static void llc_add_sap(struct llc_sap *sap)
|
static void llc_add_sap(struct llc_sap *sap)
|
||||||
{
|
{
|
||||||
write_lock_bh(&llc_sap_list_lock);
|
|
||||||
list_add_tail(&sap->node, &llc_sap_list);
|
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);
|
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
|
* llc_sap_find - searchs a SAP in station
|
||||||
* @sap_value: sap to be found
|
* @sap_value: sap to be found
|
||||||
*
|
*
|
||||||
* Searchs for a sap in the sap list of the LLC's station upon the sap ID.
|
* 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.
|
* Returns the sap or %NULL if not found.
|
||||||
*/
|
*/
|
||||||
struct llc_sap *llc_sap_find(unsigned char sap_value)
|
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;
|
struct llc_sap* sap;
|
||||||
|
|
||||||
read_lock_bh(&llc_sap_list_lock);
|
read_lock_bh(&llc_sap_list_lock);
|
||||||
list_for_each_entry(sap, &llc_sap_list, node)
|
sap = __llc_sap_find(sap_value);
|
||||||
if (sap->laddr.lsap == sap_value)
|
if (sap)
|
||||||
goto out;
|
llc_sap_hold(sap);
|
||||||
sap = NULL;
|
|
||||||
out:
|
|
||||||
read_unlock_bh(&llc_sap_list_lock);
|
read_unlock_bh(&llc_sap_list_lock);
|
||||||
return sap;
|
return sap;
|
||||||
}
|
}
|
||||||
@ -106,19 +117,20 @@ struct llc_sap *llc_sap_open(unsigned char lsap,
|
|||||||
struct packet_type *pt,
|
struct packet_type *pt,
|
||||||
struct net_device *orig_dev))
|
struct net_device *orig_dev))
|
||||||
{
|
{
|
||||||
struct llc_sap *sap = llc_sap_find(lsap);
|
struct llc_sap *sap = NULL;
|
||||||
|
|
||||||
if (sap) { /* SAP already exists */
|
write_lock_bh(&llc_sap_list_lock);
|
||||||
sap = NULL;
|
if (__llc_sap_find(lsap)) /* SAP already exists */
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
sap = llc_sap_alloc();
|
sap = llc_sap_alloc();
|
||||||
if (!sap)
|
if (!sap)
|
||||||
goto out;
|
goto out;
|
||||||
sap->laddr.lsap = lsap;
|
sap->laddr.lsap = lsap;
|
||||||
sap->rcv_func = func;
|
sap->rcv_func = func;
|
||||||
|
llc_sap_hold(sap);
|
||||||
llc_add_sap(sap);
|
llc_add_sap(sap);
|
||||||
out:
|
out:
|
||||||
|
write_unlock_bh(&llc_sap_list_lock);
|
||||||
return sap;
|
return sap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,17 +166,22 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
|
|||||||
*/
|
*/
|
||||||
if (sap->rcv_func) {
|
if (sap->rcv_func) {
|
||||||
sap->rcv_func(skb, dev, pt, orig_dev);
|
sap->rcv_func(skb, dev, pt, orig_dev);
|
||||||
goto out;
|
goto out_put;
|
||||||
}
|
}
|
||||||
dest = llc_pdu_type(skb);
|
dest = llc_pdu_type(skb);
|
||||||
if (unlikely(!dest || !llc_type_handlers[dest - 1]))
|
if (unlikely(!dest || !llc_type_handlers[dest - 1]))
|
||||||
goto drop;
|
goto drop_put;
|
||||||
llc_type_handlers[dest - 1](sap, skb);
|
llc_type_handlers[dest - 1](sap, skb);
|
||||||
|
out_put:
|
||||||
|
llc_sap_put(sap);
|
||||||
out:
|
out:
|
||||||
return 0;
|
return 0;
|
||||||
drop:
|
drop:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
goto out;
|
goto out;
|
||||||
|
drop_put:
|
||||||
|
kfree_skb(skb);
|
||||||
|
goto out_put;
|
||||||
handle_station:
|
handle_station:
|
||||||
if (!llc_station_handler)
|
if (!llc_station_handler)
|
||||||
goto drop;
|
goto drop;
|
||||||
|
Loading…
Reference in New Issue
Block a user