* [PATCH -v2 0/8] More l2cap rewrite
@ 2011-06-08 15:18 Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 1/8] Bluetooth: Merge l2cap_chan_create() in the l2cap_sock_alloc() Gustavo F. Padovan
0 siblings, 1 reply; 9+ messages in thread
From: Gustavo F. Padovan @ 2011-06-08 15:18 UTC (permalink / raw)
To: linux-bluetooth
Second version of the patches that introduce an C API on l2cap_core.c.
-----
changes from v1
- changed function names as suggested by Mat.
- fixed a bug with the new API
Gustavo F. Padovan (8):
Bluetooth: Merge l2cap_chan_create() in the l2cap_sock_alloc()
Bluetooth: Add l2cap_chan_ops abstraction
Bluetooth: add recv() callback to l2cap_chan_ops
Bluetooth: add close() callback to l2cap_chan_ops
Bluetooth: Add state tracking to struct l2cap_chan
Bluetooth: Add refcnt to struct l2cap_chan
Bluetooth: Make timer functions generic
Bluetooth: keep reference if any ERTM timer is enabled
include/net/bluetooth/l2cap.h | 38 ++++--
net/bluetooth/l2cap_core.c | 303 +++++++++++++++++++++--------------------
net/bluetooth/l2cap_sock.c | 77 +++++++++--
3 files changed, 245 insertions(+), 173 deletions(-)
--
1.7.5.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH -v2 1/8] Bluetooth: Merge l2cap_chan_create() in the l2cap_sock_alloc()
2011-06-08 15:18 [PATCH -v2 0/8] More l2cap rewrite Gustavo F. Padovan
@ 2011-06-08 15:18 ` Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 2/8] Bluetooth: Add l2cap_chan_ops abstraction Gustavo F. Padovan
0 siblings, 1 reply; 9+ messages in thread
From: Gustavo F. Padovan @ 2011-06-08 15:18 UTC (permalink / raw)
To: linux-bluetooth
As a first step to remove l2cap_sock_alloc() and l2cap_sock_init() from
l2cap_core.c
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
net/bluetooth/l2cap_core.c | 18 +++---------------
net/bluetooth/l2cap_sock.c | 18 +++++++++---------
2 files changed, 12 insertions(+), 24 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index bb451f3..aa3b057 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -846,13 +846,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
if (!sk)
goto clean;
- chan = l2cap_chan_create(sk);
- if (!chan) {
- l2cap_sock_kill(sk);
- goto clean;
- }
-
- l2cap_pi(sk)->chan = chan;
+ chan = l2cap_pi(sk)->chan;
write_lock_bh(&conn->chan_lock);
@@ -2339,14 +2333,6 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
if (!sk)
goto response;
- chan = l2cap_chan_create(sk);
- if (!chan) {
- l2cap_sock_kill(sk);
- goto response;
- }
-
- l2cap_pi(sk)->chan = chan;
-
write_lock_bh(&conn->chan_lock);
/* Check if we already have channel with that dcid */
@@ -2359,6 +2345,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
hci_conn_hold(conn->hcon);
+ chan = l2cap_pi(sk)->chan;
+
l2cap_sock_init(sk, parent);
bacpy(&bt_sk(sk)->src, conn->src);
bacpy(&bt_sk(sk)->dst, conn->dst);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index ab81894..2f4fd57 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -853,6 +853,7 @@ static struct proto l2cap_proto = {
struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
{
struct sock *sk;
+ struct l2cap_chan *chan;
sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto);
if (!sk)
@@ -869,6 +870,14 @@ struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, g
sk->sk_protocol = proto;
sk->sk_state = BT_OPEN;
+ chan = l2cap_chan_create(sk);
+ if (!chan) {
+ l2cap_sock_kill(sk);
+ return NULL;
+ }
+
+ l2cap_pi(sk)->chan = chan;
+
return sk;
}
@@ -876,7 +885,6 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
int kern)
{
struct sock *sk;
- struct l2cap_chan *chan;
BT_DBG("sock %p", sock);
@@ -895,14 +903,6 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
if (!sk)
return -ENOMEM;
- chan = l2cap_chan_create(sk);
- if (!chan) {
- l2cap_sock_kill(sk);
- return -ENOMEM;
- }
-
- l2cap_pi(sk)->chan = chan;
-
l2cap_sock_init(sk, NULL);
return 0;
}
--
1.7.5.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH -v2 2/8] Bluetooth: Add l2cap_chan_ops abstraction
2011-06-08 15:18 ` [PATCH -v2 1/8] Bluetooth: Merge l2cap_chan_create() in the l2cap_sock_alloc() Gustavo F. Padovan
@ 2011-06-08 15:18 ` Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 3/8] Bluetooth: add recv() callback to l2cap_chan_ops Gustavo F. Padovan
0 siblings, 1 reply; 9+ messages in thread
From: Gustavo F. Padovan @ 2011-06-08 15:18 UTC (permalink / raw)
To: linux-bluetooth
Add an abstraction layer between L2CAP core and its users (only
l2cap_sock.c now). The first function implemented is new_connection() that
replaces calls to l2cap_sock_alloc() in l2cap_core.c
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
include/net/bluetooth/l2cap.h | 12 +++++++++---
net/bluetooth/l2cap_core.c | 17 +++++++----------
net/bluetooth/l2cap_sock.c | 29 +++++++++++++++++++++++++++--
3 files changed, 43 insertions(+), 15 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 0529d27..d3a1509 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -354,6 +354,15 @@ struct l2cap_chan {
struct list_head list;
struct list_head global_l;
+
+ void *data;
+ struct l2cap_ops *ops;
+};
+
+struct l2cap_ops {
+ char *name;
+
+ struct l2cap_chan *(*new_connection) (void *data);
};
struct l2cap_conn {
@@ -460,9 +469,6 @@ int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm);
int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid);
void l2cap_sock_kill(struct sock *sk);
-void l2cap_sock_init(struct sock *sk, struct sock *parent);
-struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
- int proto, gfp_t prio);
struct l2cap_chan *l2cap_chan_create(struct sock *sk);
void l2cap_chan_close(struct l2cap_chan *chan, int reason);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index aa3b057..add412e 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -842,18 +842,16 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
goto clean;
}
- sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
- if (!sk)
+ chan = pchan->ops->new_connection(pchan->data);
+ if (!chan)
goto clean;
- chan = l2cap_pi(sk)->chan;
+ sk = chan->sk;
write_lock_bh(&conn->chan_lock);
hci_conn_hold(conn->hcon);
- l2cap_sock_init(sk, parent);
-
bacpy(&bt_sk(sk)->src, conn->src);
bacpy(&bt_sk(sk)->dst, conn->dst);
@@ -2329,10 +2327,12 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
goto response;
}
- sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
- if (!sk)
+ chan = pchan->ops->new_connection(pchan->data);
+ if (!chan)
goto response;
+ sk = chan->sk;
+
write_lock_bh(&conn->chan_lock);
/* Check if we already have channel with that dcid */
@@ -2345,9 +2345,6 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
hci_conn_hold(conn->hcon);
- chan = l2cap_pi(sk)->chan;
-
- l2cap_sock_init(sk, parent);
bacpy(&bt_sk(sk)->src, conn->src);
bacpy(&bt_sk(sk)->dst, conn->dst);
chan->psm = psm;
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 2f4fd57..4050ede 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -31,6 +31,8 @@
#include <net/bluetooth/l2cap.h>
static const struct proto_ops l2cap_sock_ops;
+static void l2cap_sock_init(struct sock *sk, struct sock *parent);
+static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio);
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{
@@ -773,6 +775,25 @@ static int l2cap_sock_release(struct socket *sock)
return err;
}
+static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
+{
+ struct sock *sk, *parent = data;
+
+ sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP,
+ GFP_ATOMIC);
+ if (!sk)
+ return NULL;
+
+ l2cap_sock_init(sk, parent);
+
+ return l2cap_pi(sk)->chan;
+}
+
+static struct l2cap_ops l2cap_chan_ops = {
+ .name = "L2CAP Socket Interface",
+ .new_connection = l2cap_sock_new_connection_cb,
+};
+
static void l2cap_sock_destruct(struct sock *sk)
{
BT_DBG("sk %p", sk);
@@ -781,7 +802,7 @@ static void l2cap_sock_destruct(struct sock *sk)
skb_queue_purge(&sk->sk_write_queue);
}
-void l2cap_sock_init(struct sock *sk, struct sock *parent)
+static void l2cap_sock_init(struct sock *sk, struct sock *parent)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct l2cap_chan *chan = pi->chan;
@@ -838,10 +859,14 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent)
chan->force_reliable = 0;
chan->flushable = BT_FLUSHABLE_OFF;
chan->force_active = BT_POWER_FORCE_ACTIVE_ON;
+
}
/* Default config options */
chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+
+ chan->data = sk;
+ chan->ops = &l2cap_chan_ops;
}
static struct proto l2cap_proto = {
@@ -850,7 +875,7 @@ static struct proto l2cap_proto = {
.obj_size = sizeof(struct l2cap_pinfo)
};
-struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
+static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
{
struct sock *sk;
struct l2cap_chan *chan;
--
1.7.5.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH -v2 3/8] Bluetooth: add recv() callback to l2cap_chan_ops
2011-06-08 15:18 ` [PATCH -v2 2/8] Bluetooth: Add l2cap_chan_ops abstraction Gustavo F. Padovan
@ 2011-06-08 15:18 ` Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 4/8] Bluetooth: add close() " Gustavo F. Padovan
0 siblings, 1 reply; 9+ messages in thread
From: Gustavo F. Padovan @ 2011-06-08 15:18 UTC (permalink / raw)
To: linux-bluetooth
This abstracts the call to sock_queue_recv_skb() into
l2cap_chan_ops->recv().
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
include/net/bluetooth/l2cap.h | 1 +
net/bluetooth/l2cap_core.c | 16 ++++++++--------
net/bluetooth/l2cap_sock.c | 8 ++++++++
3 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index d3a1509..05bb254 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -363,6 +363,7 @@ struct l2cap_ops {
char *name;
struct l2cap_chan *(*new_connection) (void *data);
+ int (*recv) (void *data, struct sk_buff *skb);
};
struct l2cap_conn {
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index add412e..fa9a4ab 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1698,7 +1698,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
if (!nskb)
continue;
- if (sock_queue_rcv_skb(sk, nskb))
+ if (chan->ops->recv(chan->data, nskb))
kfree_skb(nskb);
}
read_unlock(&conn->chan_lock);
@@ -3124,7 +3124,7 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk
if (chan->conn_state & L2CAP_CONN_SAR_SDU)
goto drop;
- return sock_queue_rcv_skb(chan->sk, skb);
+ return chan->ops->recv(chan->data, skb);
case L2CAP_SDU_START:
if (chan->conn_state & L2CAP_CONN_SAR_SDU)
@@ -3190,7 +3190,7 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk
return -ENOMEM;
}
- err = sock_queue_rcv_skb(chan->sk, _skb);
+ err = chan->ops->recv(chan->data, _skb);
if (err < 0) {
kfree_skb(_skb);
chan->conn_state |= L2CAP_CONN_SAR_RETRY;
@@ -3358,7 +3358,7 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf
break;
}
- err = sock_queue_rcv_skb(chan->sk, skb);
+ err = chan->ops->recv(chan->data, skb);
if (!err)
return 0;
@@ -3419,7 +3419,7 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf
if (chan->partial_sdu_len == chan->sdu_len) {
_skb = skb_clone(chan->sdu, GFP_ATOMIC);
- err = sock_queue_rcv_skb(chan->sk, _skb);
+ err = chan->ops->recv(chan->data, _skb);
if (err < 0)
kfree_skb(_skb);
}
@@ -3886,7 +3886,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
if (chan->imtu < skb->len)
goto drop;
- if (!sock_queue_rcv_skb(sk, skb))
+ if (!chan->ops->recv(chan->data, skb))
goto done;
break;
@@ -3964,7 +3964,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
if (l2cap_pi(sk)->chan->imtu < skb->len)
goto drop;
- if (!sock_queue_rcv_skb(sk, skb))
+ if (!chan->ops->recv(chan->data, skb))
goto done;
drop:
@@ -3997,7 +3997,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct
if (l2cap_pi(sk)->chan->imtu < skb->len)
goto drop;
- if (!sock_queue_rcv_skb(sk, skb))
+ if (!chan->ops->recv(chan->data, skb))
goto done;
drop:
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 4050ede..28cdc7e 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -789,9 +789,17 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
return l2cap_pi(sk)->chan;
}
+static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
+{
+ struct sock *sk = data;
+
+ return sock_queue_rcv_skb(sk, skb);
+}
+
static struct l2cap_ops l2cap_chan_ops = {
.name = "L2CAP Socket Interface",
.new_connection = l2cap_sock_new_connection_cb,
+ .recv = l2cap_sock_recv_cb,
};
static void l2cap_sock_destruct(struct sock *sk)
--
1.7.5.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH -v2 4/8] Bluetooth: add close() callback to l2cap_chan_ops
2011-06-08 15:18 ` [PATCH -v2 3/8] Bluetooth: add recv() callback to l2cap_chan_ops Gustavo F. Padovan
@ 2011-06-08 15:18 ` Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 5/8] Bluetooth: Add state tracking to struct l2cap_chan Gustavo F. Padovan
0 siblings, 1 reply; 9+ messages in thread
From: Gustavo F. Padovan @ 2011-06-08 15:18 UTC (permalink / raw)
To: linux-bluetooth
close() calls l2cap_sock_kill() on l2cap_sock.c
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
include/net/bluetooth/l2cap.h | 3 +--
net/bluetooth/l2cap_core.c | 17 +++++++++--------
net/bluetooth/l2cap_sock.c | 10 +++++++++-
3 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 05bb254..0ad61d0 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -364,6 +364,7 @@ struct l2cap_ops {
struct l2cap_chan *(*new_connection) (void *data);
int (*recv) (void *data, struct sk_buff *skb);
+ void (*close) (void *data);
};
struct l2cap_conn {
@@ -469,8 +470,6 @@ int __l2cap_wait_ack(struct sock *sk);
int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm);
int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid);
-void l2cap_sock_kill(struct sock *sk);
-
struct l2cap_chan *l2cap_chan_create(struct sock *sk);
void l2cap_chan_close(struct l2cap_chan *chan, int reason);
void l2cap_chan_destroy(struct l2cap_chan *chan);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index fa9a4ab..d832cb1 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -254,7 +254,7 @@ static void l2cap_chan_timeout(unsigned long arg)
bh_unlock_sock(sk);
- l2cap_sock_kill(sk);
+ chan->ops->close(chan->data);
sock_put(sk);
}
@@ -391,11 +391,12 @@ static void l2cap_chan_cleanup_listen(struct sock *parent)
/* Close not yet accepted channels */
while ((sk = bt_accept_dequeue(parent, NULL))) {
- l2cap_chan_clear_timer(l2cap_pi(sk)->chan);
+ struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+ l2cap_chan_clear_timer(chan);
lock_sock(sk);
- l2cap_chan_close(l2cap_pi(sk)->chan, ECONNRESET);
+ l2cap_chan_close(chan, ECONNRESET);
release_sock(sk);
- l2cap_sock_kill(sk);
+ chan->ops->close(chan->data);
}
parent->sk_state = BT_CLOSED;
@@ -993,7 +994,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
bh_lock_sock(sk);
l2cap_chan_del(chan, err);
bh_unlock_sock(sk);
- l2cap_sock_kill(sk);
+ chan->ops->close(chan->data);
}
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
@@ -2339,7 +2340,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
if (__l2cap_get_chan_by_dcid(conn, scid)) {
write_unlock_bh(&conn->chan_lock);
sock_set_flag(sk, SOCK_ZAPPED);
- l2cap_sock_kill(sk);
+ chan->ops->close(chan->data);
goto response;
}
@@ -2712,7 +2713,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
l2cap_chan_del(chan, ECONNRESET);
bh_unlock_sock(sk);
- l2cap_sock_kill(sk);
+ chan->ops->close(chan->data);
return 0;
}
@@ -2746,7 +2747,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
l2cap_chan_del(chan, 0);
bh_unlock_sock(sk);
- l2cap_sock_kill(sk);
+ chan->ops->close(chan->data);
return 0;
}
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 28cdc7e..9f15a16 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -713,7 +713,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
/* Kill socket (only if zapped and orphan)
* Must be called on unlocked socket.
*/
-void l2cap_sock_kill(struct sock *sk)
+static void l2cap_sock_kill(struct sock *sk)
{
if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
return;
@@ -796,10 +796,18 @@ static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
return sock_queue_rcv_skb(sk, skb);
}
+static void l2cap_sock_close_cb(void *data)
+{
+ struct sock *sk = data;
+
+ l2cap_sock_kill(sk);
+}
+
static struct l2cap_ops l2cap_chan_ops = {
.name = "L2CAP Socket Interface",
.new_connection = l2cap_sock_new_connection_cb,
.recv = l2cap_sock_recv_cb,
+ .close = l2cap_sock_close_cb,
};
static void l2cap_sock_destruct(struct sock *sk)
--
1.7.5.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH -v2 5/8] Bluetooth: Add state tracking to struct l2cap_chan
2011-06-08 15:18 ` [PATCH -v2 4/8] Bluetooth: add close() " Gustavo F. Padovan
@ 2011-06-08 15:18 ` Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 6/8] Bluetooth: Add refcnt " Gustavo F. Padovan
0 siblings, 1 reply; 9+ messages in thread
From: Gustavo F. Padovan @ 2011-06-08 15:18 UTC (permalink / raw)
To: linux-bluetooth
Now socket state is tracked by struct sock and channel state is tracked by
chan->state. At this point both says the same, but this is going to change
when we add AMP Support for example.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
include/net/bluetooth/l2cap.h | 3 +
net/bluetooth/l2cap_core.c | 113 +++++++++++++++++++++-------------------
net/bluetooth/l2cap_sock.c | 12 ++++
3 files changed, 74 insertions(+), 54 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 0ad61d0..68c8724 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -287,6 +287,8 @@ struct l2cap_chan {
struct l2cap_conn *conn;
+ __u8 state;
+
__le16 psm;
__u16 dcid;
__u16 scid;
@@ -365,6 +367,7 @@ struct l2cap_ops {
struct l2cap_chan *(*new_connection) (void *data);
int (*recv) (void *data, struct sk_buff *skb);
void (*close) (void *data);
+ void (*state_change) (void *data, int state);
};
struct l2cap_conn {
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index d832cb1..b07adf8 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -210,27 +210,33 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
static void l2cap_chan_set_timer(struct l2cap_chan *chan, long timeout)
{
- BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->sk->sk_state,
- timeout);
+ BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout);
+
if (!mod_timer(&chan->chan_timer, jiffies + timeout))
sock_hold(chan->sk);
}
static void l2cap_chan_clear_timer(struct l2cap_chan *chan)
{
- BT_DBG("chan %p state %d", chan, chan->sk->sk_state);
+ BT_DBG("chan %p state %d", chan, chan->state);
if (timer_pending(&chan->chan_timer) && del_timer(&chan->chan_timer))
__sock_put(chan->sk);
}
+static void l2cap_state_change(struct l2cap_chan *chan, int state)
+{
+ chan->state = state;
+ chan->ops->state_change(chan->data, state);
+}
+
static void l2cap_chan_timeout(unsigned long arg)
{
struct l2cap_chan *chan = (struct l2cap_chan *) arg;
struct sock *sk = chan->sk;
int reason;
- BT_DBG("chan %p state %d", chan, sk->sk_state);
+ BT_DBG("chan %p state %d", chan, chan->state);
bh_lock_sock(sk);
@@ -242,9 +248,9 @@ static void l2cap_chan_timeout(unsigned long arg)
return;
}
- if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
+ if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
reason = ECONNREFUSED;
- else if (sk->sk_state == BT_CONNECT &&
+ else if (chan->state == BT_CONNECT &&
chan->sec_level != BT_SECURITY_SDP)
reason = ECONNREFUSED;
else
@@ -274,6 +280,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan);
+ chan->state = BT_OPEN;
+
return chan;
}
@@ -348,7 +356,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
hci_conn_put(conn->hcon);
}
- sk->sk_state = BT_CLOSED;
+ l2cap_state_change(chan, BT_CLOSED);
sock_set_flag(sk, SOCK_ZAPPED);
if (err)
@@ -398,9 +406,6 @@ static void l2cap_chan_cleanup_listen(struct sock *parent)
release_sock(sk);
chan->ops->close(chan->data);
}
-
- parent->sk_state = BT_CLOSED;
- sock_set_flag(parent, SOCK_ZAPPED);
}
void l2cap_chan_close(struct l2cap_chan *chan, int reason)
@@ -408,11 +413,14 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
struct l2cap_conn *conn = chan->conn;
struct sock *sk = chan->sk;
- BT_DBG("chan %p state %d socket %p", chan, sk->sk_state, sk->sk_socket);
+ BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
- switch (sk->sk_state) {
+ switch (chan->state) {
case BT_LISTEN:
l2cap_chan_cleanup_listen(sk);
+
+ l2cap_state_change(chan, BT_CLOSED);
+ sock_set_flag(sk, SOCK_ZAPPED);
break;
case BT_CONNECTED:
@@ -436,7 +444,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
result = L2CAP_CR_SEC_BLOCK;
else
result = L2CAP_CR_BAD_PSM;
- sk->sk_state = BT_DISCONN;
+ l2cap_state_change(chan, BT_DISCONN);
rsp.scid = cpu_to_le16(chan->dcid);
rsp.dcid = cpu_to_le16(chan->scid);
@@ -548,13 +556,11 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
{
struct sk_buff *skb;
struct l2cap_hdr *lh;
- struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
struct l2cap_conn *conn = chan->conn;
- struct sock *sk = (struct sock *)pi;
int count, hlen = L2CAP_HDR_SIZE + 2;
u8 flags;
- if (sk->sk_state != BT_CONNECTED)
+ if (chan->state != BT_CONNECTED)
return;
if (chan->fcs == L2CAP_FCS_CRC16)
@@ -689,7 +695,7 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
l2cap_send_cmd(conn, l2cap_get_ident(conn),
L2CAP_DISCONN_REQ, sizeof(req), &req);
- sk->sk_state = BT_DISCONN;
+ l2cap_state_change(chan, BT_DISCONN);
sk->sk_err = err;
}
@@ -712,7 +718,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
continue;
}
- if (sk->sk_state == BT_CONNECT) {
+ if (chan->state == BT_CONNECT) {
struct l2cap_conn_req req;
if (!l2cap_check_security(chan) ||
@@ -728,7 +734,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
/* l2cap_chan_close() calls list_del(chan)
* so release the lock */
read_unlock_bh(&conn->chan_lock);
- l2cap_chan_close(chan, ECONNRESET);
+ l2cap_chan_close(chan, ECONNRESET);
read_lock_bh(&conn->chan_lock);
bh_unlock_sock(sk);
continue;
@@ -743,7 +749,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
sizeof(req), &req);
- } else if (sk->sk_state == BT_CONNECT2) {
+ } else if (chan->state == BT_CONNECT2) {
struct l2cap_conn_rsp rsp;
char buf[128];
rsp.scid = cpu_to_le16(chan->dcid);
@@ -757,7 +763,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
parent->sk_data_ready(parent, 0);
} else {
- sk->sk_state = BT_CONFIG;
+ l2cap_state_change(chan, BT_CONFIG);
rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
}
@@ -799,7 +805,7 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdadd
list_for_each_entry(c, &chan_list, global_l) {
struct sock *sk = c->sk;
- if (state && sk->sk_state != state)
+ if (state && c->state != state)
continue;
if (c->scid == cid) {
@@ -862,7 +868,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
- sk->sk_state = BT_CONNECTED;
+ l2cap_state_change(chan, BT_CONNECTED);
parent->sk_data_ready(parent, 0);
write_unlock_bh(&conn->chan_lock);
@@ -889,15 +895,15 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
if (conn->hcon->type == LE_LINK) {
l2cap_chan_clear_timer(chan);
- sk->sk_state = BT_CONNECTED;
+ l2cap_state_change(chan, BT_CONNECTED);
sk->sk_state_change(sk);
}
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
l2cap_chan_clear_timer(chan);
- sk->sk_state = BT_CONNECTED;
+ l2cap_state_change(chan, BT_CONNECTED);
sk->sk_state_change(sk);
- } else if (sk->sk_state == BT_CONNECT)
+ } else if (chan->state == BT_CONNECT)
l2cap_do_start(chan);
bh_unlock_sock(sk);
@@ -1025,7 +1031,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr
list_for_each_entry(c, &chan_list, global_l) {
struct sock *sk = c->sk;
- if (state && sk->sk_state != state)
+ if (state && c->state != state)
continue;
if (c->psm == psm) {
@@ -1092,14 +1098,14 @@ int l2cap_chan_connect(struct l2cap_chan *chan)
l2cap_chan_add(conn, chan);
- sk->sk_state = BT_CONNECT;
+ l2cap_state_change(chan, BT_CONNECT);
l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
if (hcon->state == BT_CONNECTED) {
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
l2cap_chan_clear_timer(chan);
if (l2cap_check_security(chan))
- sk->sk_state = BT_CONNECTED;
+ l2cap_state_change(chan, BT_CONNECTED);
} else
l2cap_do_start(chan);
}
@@ -1288,11 +1294,10 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
int l2cap_ertm_send(struct l2cap_chan *chan)
{
struct sk_buff *skb, *tx_skb;
- struct sock *sk = chan->sk;
u16 control, fcs;
int nsent = 0;
- if (sk->sk_state != BT_CONNECTED)
+ if (chan->state != BT_CONNECTED)
return -ENOTCONN;
while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
@@ -1668,7 +1673,7 @@ static void l2cap_chan_ready(struct sock *sk)
/* Outgoing channel.
* Wake up socket sleeping on connect.
*/
- sk->sk_state = BT_CONNECTED;
+ l2cap_state_change(chan, BT_CONNECTED);
sk->sk_state_change(sk);
} else {
/* Incoming channel.
@@ -2364,22 +2369,22 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
if (l2cap_check_security(chan)) {
if (bt_sk(sk)->defer_setup) {
- sk->sk_state = BT_CONNECT2;
+ l2cap_state_change(chan, BT_CONNECT2);
result = L2CAP_CR_PEND;
status = L2CAP_CS_AUTHOR_PEND;
parent->sk_data_ready(parent, 0);
} else {
- sk->sk_state = BT_CONFIG;
+ l2cap_state_change(chan, BT_CONFIG);
result = L2CAP_CR_SUCCESS;
status = L2CAP_CS_NO_INFO;
}
} else {
- sk->sk_state = BT_CONNECT2;
+ l2cap_state_change(chan, BT_CONNECT2);
result = L2CAP_CR_PEND;
status = L2CAP_CS_AUTHEN_PEND;
}
} else {
- sk->sk_state = BT_CONNECT2;
+ l2cap_state_change(chan, BT_CONNECT2);
result = L2CAP_CR_PEND;
status = L2CAP_CS_NO_INFO;
}
@@ -2451,7 +2456,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
switch (result) {
case L2CAP_CR_SUCCESS:
- sk->sk_state = BT_CONFIG;
+ l2cap_state_change(chan, BT_CONFIG);
chan->ident = 0;
chan->dcid = dcid;
chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
@@ -2473,7 +2478,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
default:
/* don't delete l2cap channel if sk is owned by user */
if (sock_owned_by_user(sk)) {
- sk->sk_state = BT_DISCONN;
+ l2cap_state_change(chan, BT_DISCONN);
l2cap_chan_clear_timer(chan);
l2cap_chan_set_timer(chan, HZ / 5);
break;
@@ -2520,7 +2525,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
sk = chan->sk;
- if (sk->sk_state != BT_CONFIG) {
+ if (chan->state != BT_CONFIG) {
struct l2cap_cmd_rej rej;
rej.reason = cpu_to_le16(0x0002);
@@ -2569,7 +2574,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
if (chan->conf_state & L2CAP_CONF_INPUT_DONE) {
set_default_fcs(chan);
- sk->sk_state = BT_CONNECTED;
+ l2cap_state_change(chan, BT_CONNECTED);
chan->next_tx_seq = 0;
chan->expected_tx_seq = 0;
@@ -2661,7 +2666,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) {
set_default_fcs(chan);
- sk->sk_state = BT_CONNECTED;
+ l2cap_state_change(chan, BT_CONNECTED);
chan->next_tx_seq = 0;
chan->expected_tx_seq = 0;
skb_queue_head_init(&chan->tx_q);
@@ -2703,7 +2708,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
/* don't delete l2cap channel if sk is owned by user */
if (sock_owned_by_user(sk)) {
- sk->sk_state = BT_DISCONN;
+ l2cap_state_change(chan, BT_DISCONN);
l2cap_chan_clear_timer(chan);
l2cap_chan_set_timer(chan, HZ / 5);
bh_unlock_sock(sk);
@@ -2737,7 +2742,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
/* don't delete l2cap channel if sk is owned by user */
if (sock_owned_by_user(sk)) {
- sk->sk_state = BT_DISCONN;
+ l2cap_state_change(chan,BT_DISCONN);
l2cap_chan_clear_timer(chan);
l2cap_chan_set_timer(chan, HZ / 5);
bh_unlock_sock(sk);
@@ -3874,7 +3879,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
BT_DBG("chan %p, len %d", chan, skb->len);
- if (sk->sk_state != BT_CONNECTED)
+ if (chan->state != BT_CONNECTED)
goto drop;
switch (chan->mode) {
@@ -3959,7 +3964,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
BT_DBG("sk %p, len %d", sk, skb->len);
- if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
+ if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
goto drop;
if (l2cap_pi(sk)->chan->imtu < skb->len)
@@ -3992,7 +3997,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct
BT_DBG("sk %p, len %d", sk, skb->len);
- if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
+ if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
goto drop;
if (l2cap_pi(sk)->chan->imtu < skb->len)
@@ -4066,7 +4071,7 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
list_for_each_entry(c, &chan_list, global_l) {
struct sock *sk = c->sk;
- if (sk->sk_state != BT_LISTEN)
+ if (c->state != BT_LISTEN)
continue;
if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
@@ -4167,14 +4172,14 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
continue;
}
- if (!status && (sk->sk_state == BT_CONNECTED ||
- sk->sk_state == BT_CONFIG)) {
+ if (!status && (chan->state == BT_CONNECTED ||
+ chan->state == BT_CONFIG)) {
l2cap_check_encryption(chan, encrypt);
bh_unlock_sock(sk);
continue;
}
- if (sk->sk_state == BT_CONNECT) {
+ if (chan->state == BT_CONNECT) {
if (!status) {
struct l2cap_conn_req req;
req.scid = cpu_to_le16(chan->scid);
@@ -4189,15 +4194,15 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
l2cap_chan_clear_timer(chan);
l2cap_chan_set_timer(chan, HZ / 10);
}
- } else if (sk->sk_state == BT_CONNECT2) {
+ } else if (chan->state == BT_CONNECT2) {
struct l2cap_conn_rsp rsp;
__u16 result;
if (!status) {
- sk->sk_state = BT_CONFIG;
+ l2cap_state_change(chan, BT_CONFIG);
result = L2CAP_CR_SUCCESS;
} else {
- sk->sk_state = BT_DISCONN;
+ l2cap_state_change(chan, BT_DISCONN);
l2cap_chan_set_timer(chan, HZ / 10);
result = L2CAP_CR_SEC_BLOCK;
}
@@ -4341,7 +4346,7 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
batostr(&bt_sk(sk)->src),
batostr(&bt_sk(sk)->dst),
- sk->sk_state, __le16_to_cpu(c->psm),
+ c->state, __le16_to_cpu(c->psm),
c->scid, c->dcid, c->imtu, c->omtu,
c->sec_level, c->mode);
}
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 9f15a16..1d9c365 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -89,6 +89,8 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
chan->sec_level = BT_SECURITY_SDP;
bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
+
+ chan->state = BT_BOUND;
sk->sk_state = BT_BOUND;
done:
@@ -214,6 +216,8 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
sk->sk_max_ack_backlog = backlog;
sk->sk_ack_backlog = 0;
+
+ chan->state = BT_LISTEN;
sk->sk_state = BT_LISTEN;
done:
@@ -803,11 +807,19 @@ static void l2cap_sock_close_cb(void *data)
l2cap_sock_kill(sk);
}
+static void l2cap_sock_state_change_cb(void *data, int state)
+{
+ struct sock *sk = data;
+
+ sk->sk_state = state;
+}
+
static struct l2cap_ops l2cap_chan_ops = {
.name = "L2CAP Socket Interface",
.new_connection = l2cap_sock_new_connection_cb,
.recv = l2cap_sock_recv_cb,
.close = l2cap_sock_close_cb,
+ .state_change = l2cap_sock_state_change_cb,
};
static void l2cap_sock_destruct(struct sock *sk)
--
1.7.5.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH -v2 6/8] Bluetooth: Add refcnt to struct l2cap_chan
2011-06-08 15:18 ` [PATCH -v2 5/8] Bluetooth: Add state tracking to struct l2cap_chan Gustavo F. Padovan
@ 2011-06-08 15:18 ` Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 7/8] Bluetooth: Make timer functions generic Gustavo F. Padovan
0 siblings, 1 reply; 9+ messages in thread
From: Gustavo F. Padovan @ 2011-06-08 15:18 UTC (permalink / raw)
To: linux-bluetooth
struct l2cap_chan has now its own refcnt that is compatible with the
socket refcnt, i.e., we won't see sk_refcnt = 0 and chan->refcnt > 0.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
include/net/bluetooth/l2cap.h | 2 ++
net/bluetooth/l2cap_core.c | 30 +++++++++++++++++++++---------
2 files changed, 23 insertions(+), 9 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 68c8724..b3d953b 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -289,6 +289,8 @@ struct l2cap_chan {
__u8 state;
+ atomic_t refcnt;
+
__le16 psm;
__u16 dcid;
__u16 scid;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index b07adf8..6ae5fe6 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -78,6 +78,18 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn,
static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
/* ---- L2CAP channels ---- */
+
+static inline void chan_hold(struct l2cap_chan *c)
+{
+ atomic_inc(&c->refcnt);
+}
+
+static inline void chan_put(struct l2cap_chan *c)
+{
+ if (atomic_dec_and_test(&c->refcnt))
+ kfree(c);
+}
+
static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
{
struct l2cap_chan *c;
@@ -213,7 +225,7 @@ static void l2cap_chan_set_timer(struct l2cap_chan *chan, long timeout)
BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout);
if (!mod_timer(&chan->chan_timer, jiffies + timeout))
- sock_hold(chan->sk);
+ chan_hold(chan);
}
static void l2cap_chan_clear_timer(struct l2cap_chan *chan)
@@ -221,7 +233,7 @@ static void l2cap_chan_clear_timer(struct l2cap_chan *chan)
BT_DBG("chan %p state %d", chan, chan->state);
if (timer_pending(&chan->chan_timer) && del_timer(&chan->chan_timer))
- __sock_put(chan->sk);
+ chan_put(chan);
}
static void l2cap_state_change(struct l2cap_chan *chan, int state)
@@ -244,7 +256,7 @@ static void l2cap_chan_timeout(unsigned long arg)
/* sk is owned by user. Try again later */
l2cap_chan_set_timer(chan, HZ / 5);
bh_unlock_sock(sk);
- sock_put(sk);
+ chan_put(chan);
return;
}
@@ -261,7 +273,7 @@ static void l2cap_chan_timeout(unsigned long arg)
bh_unlock_sock(sk);
chan->ops->close(chan->data);
- sock_put(sk);
+ chan_put(chan);
}
struct l2cap_chan *l2cap_chan_create(struct sock *sk)
@@ -282,6 +294,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
chan->state = BT_OPEN;
+ atomic_set(&chan->refcnt, 1);
+
return chan;
}
@@ -291,13 +305,11 @@ void l2cap_chan_destroy(struct l2cap_chan *chan)
list_del(&chan->global_l);
write_unlock_bh(&chan_list_lock);
- kfree(chan);
+ chan_put(chan);
}
static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
{
- struct sock *sk = chan->sk;
-
BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
chan->psm, chan->dcid);
@@ -328,7 +340,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
chan->omtu = L2CAP_DEFAULT_MTU;
}
- sock_hold(sk);
+ chan_hold(chan);
list_add(&chan->list, &conn->chan_l);
}
@@ -350,7 +362,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
write_lock_bh(&conn->chan_lock);
list_del(&chan->list);
write_unlock_bh(&conn->chan_lock);
- __sock_put(sk);
+ chan_put(chan);
chan->conn = NULL;
hci_conn_put(conn->hcon);
--
1.7.5.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH -v2 7/8] Bluetooth: Make timer functions generic
2011-06-08 15:18 ` [PATCH -v2 6/8] Bluetooth: Add refcnt " Gustavo F. Padovan
@ 2011-06-08 15:18 ` Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 8/8] Bluetooth: keep reference if any ERTM timer is enabled Gustavo F. Padovan
0 siblings, 1 reply; 9+ messages in thread
From: Gustavo F. Padovan @ 2011-06-08 15:18 UTC (permalink / raw)
To: linux-bluetooth
We now plan to use l2cap_set_timer and l2cap_clear_timer in ERTM timers.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
include/net/bluetooth/l2cap.h | 2 +
net/bluetooth/l2cap_core.c | 58 ++++++++++++++++++++--------------------
2 files changed, 31 insertions(+), 29 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index b3d953b..7aaf7f7 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -439,6 +439,8 @@ struct l2cap_pinfo {
#define L2CAP_CONN_RNR_SENT 0x0200
#define L2CAP_CONN_SAR_RETRY 0x0400
+#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
+#define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
#define __mod_retrans_timer() mod_timer(&chan->retrans_timer, \
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
#define __mod_monitor_timer() mod_timer(&chan->monitor_timer, \
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 6ae5fe6..c6d008d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -220,19 +220,19 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
return 0;
}
-static void l2cap_chan_set_timer(struct l2cap_chan *chan, long timeout)
+static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
{
BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout);
- if (!mod_timer(&chan->chan_timer, jiffies + timeout))
+ if (!mod_timer(timer, jiffies + timeout))
chan_hold(chan);
}
-static void l2cap_chan_clear_timer(struct l2cap_chan *chan)
+static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
{
BT_DBG("chan %p state %d", chan, chan->state);
- if (timer_pending(&chan->chan_timer) && del_timer(&chan->chan_timer))
+ if (timer_pending(timer) && del_timer(timer))
chan_put(chan);
}
@@ -254,7 +254,7 @@ static void l2cap_chan_timeout(unsigned long arg)
if (sock_owned_by_user(sk)) {
/* sk is owned by user. Try again later */
- l2cap_chan_set_timer(chan, HZ / 5);
+ __set_chan_timer(chan, HZ / 5);
bh_unlock_sock(sk);
chan_put(chan);
return;
@@ -353,7 +353,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
struct l2cap_conn *conn = chan->conn;
struct sock *parent = bt_sk(sk)->parent;
- l2cap_chan_clear_timer(chan);
+ __clear_chan_timer(chan);
BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
@@ -412,7 +412,7 @@ static void l2cap_chan_cleanup_listen(struct sock *parent)
/* Close not yet accepted channels */
while ((sk = bt_accept_dequeue(parent, NULL))) {
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
- l2cap_chan_clear_timer(chan);
+ __clear_chan_timer(chan);
lock_sock(sk);
l2cap_chan_close(chan, ECONNRESET);
release_sock(sk);
@@ -439,8 +439,8 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
case BT_CONFIG:
if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
conn->hcon->type == ACL_LINK) {
- l2cap_chan_clear_timer(chan);
- l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
+ __clear_chan_timer(chan);
+ __set_chan_timer(chan, sk->sk_sndtimeo);
l2cap_send_disconn_req(conn, chan, reason);
} else
l2cap_chan_del(chan, reason);
@@ -878,7 +878,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
__l2cap_chan_add(conn, chan);
- l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
+ __set_chan_timer(chan, sk->sk_sndtimeo);
l2cap_state_change(chan, BT_CONNECTED);
parent->sk_data_ready(parent, 0);
@@ -906,13 +906,13 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
bh_lock_sock(sk);
if (conn->hcon->type == LE_LINK) {
- l2cap_chan_clear_timer(chan);
+ __clear_chan_timer(chan);
l2cap_state_change(chan, BT_CONNECTED);
sk->sk_state_change(sk);
}
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
- l2cap_chan_clear_timer(chan);
+ __clear_chan_timer(chan);
l2cap_state_change(chan, BT_CONNECTED);
sk->sk_state_change(sk);
} else if (chan->state == BT_CONNECT)
@@ -1111,11 +1111,11 @@ int l2cap_chan_connect(struct l2cap_chan *chan)
l2cap_chan_add(conn, chan);
l2cap_state_change(chan, BT_CONNECT);
- l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
+ __set_chan_timer(chan, sk->sk_sndtimeo);
if (hcon->state == BT_CONNECTED) {
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
- l2cap_chan_clear_timer(chan);
+ __clear_chan_timer(chan);
if (l2cap_check_security(chan))
l2cap_state_change(chan, BT_CONNECTED);
} else
@@ -1679,7 +1679,7 @@ static void l2cap_chan_ready(struct sock *sk)
BT_DBG("sk %p, parent %p", sk, parent);
chan->conf_state = 0;
- l2cap_chan_clear_timer(chan);
+ __clear_chan_timer(chan);
if (!parent) {
/* Outgoing channel.
@@ -2374,7 +2374,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
dcid = chan->scid;
- l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
+ __set_chan_timer(chan, sk->sk_sndtimeo);
chan->ident = cmd->ident;
@@ -2491,8 +2491,8 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
/* don't delete l2cap channel if sk is owned by user */
if (sock_owned_by_user(sk)) {
l2cap_state_change(chan, BT_DISCONN);
- l2cap_chan_clear_timer(chan);
- l2cap_chan_set_timer(chan, HZ / 5);
+ __clear_chan_timer(chan);
+ __set_chan_timer(chan, HZ / 5);
break;
}
@@ -2665,7 +2665,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
default:
sk->sk_err = ECONNRESET;
- l2cap_chan_set_timer(chan, HZ * 5);
+ __set_chan_timer(chan, HZ * 5);
l2cap_send_disconn_req(conn, chan, ECONNRESET);
goto done;
}
@@ -2721,8 +2721,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
/* don't delete l2cap channel if sk is owned by user */
if (sock_owned_by_user(sk)) {
l2cap_state_change(chan, BT_DISCONN);
- l2cap_chan_clear_timer(chan);
- l2cap_chan_set_timer(chan, HZ / 5);
+ __clear_chan_timer(chan);
+ __set_chan_timer(chan, HZ / 5);
bh_unlock_sock(sk);
return 0;
}
@@ -2755,8 +2755,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
/* don't delete l2cap channel if sk is owned by user */
if (sock_owned_by_user(sk)) {
l2cap_state_change(chan,BT_DISCONN);
- l2cap_chan_clear_timer(chan);
- l2cap_chan_set_timer(chan, HZ / 5);
+ __clear_chan_timer(chan);
+ __set_chan_timer(chan, HZ / 5);
bh_unlock_sock(sk);
return 0;
}
@@ -4152,13 +4152,13 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
if (encrypt == 0x00) {
if (chan->sec_level == BT_SECURITY_MEDIUM) {
- l2cap_chan_clear_timer(chan);
- l2cap_chan_set_timer(chan, HZ * 5);
+ __clear_chan_timer(chan);
+ __set_chan_timer(chan, HZ * 5);
} else if (chan->sec_level == BT_SECURITY_HIGH)
l2cap_chan_close(chan, ECONNREFUSED);
} else {
if (chan->sec_level == BT_SECURITY_MEDIUM)
- l2cap_chan_clear_timer(chan);
+ __clear_chan_timer(chan);
}
}
@@ -4203,8 +4203,8 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
l2cap_send_cmd(conn, chan->ident,
L2CAP_CONN_REQ, sizeof(req), &req);
} else {
- l2cap_chan_clear_timer(chan);
- l2cap_chan_set_timer(chan, HZ / 10);
+ __clear_chan_timer(chan);
+ __set_chan_timer(chan, HZ / 10);
}
} else if (chan->state == BT_CONNECT2) {
struct l2cap_conn_rsp rsp;
@@ -4215,7 +4215,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
result = L2CAP_CR_SUCCESS;
} else {
l2cap_state_change(chan, BT_DISCONN);
- l2cap_chan_set_timer(chan, HZ / 10);
+ __set_chan_timer(chan, HZ / 10);
result = L2CAP_CR_SEC_BLOCK;
}
--
1.7.5.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH -v2 8/8] Bluetooth: keep reference if any ERTM timer is enabled
2011-06-08 15:18 ` [PATCH -v2 7/8] Bluetooth: Make timer functions generic Gustavo F. Padovan
@ 2011-06-08 15:18 ` Gustavo F. Padovan
0 siblings, 0 replies; 9+ messages in thread
From: Gustavo F. Padovan @ 2011-06-08 15:18 UTC (permalink / raw)
To: linux-bluetooth
ERTM use the generic L2CAP timer functions to keep a reference to the
channel. This is useful for avoiding crashes.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
include/net/bluetooth/l2cap.h | 15 ++++++++-----
net/bluetooth/l2cap_core.c | 44 ++++++++++++++++++++--------------------
2 files changed, 31 insertions(+), 28 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 7aaf7f7..c284be0 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -441,12 +441,15 @@ struct l2cap_pinfo {
#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
#define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
-#define __mod_retrans_timer() mod_timer(&chan->retrans_timer, \
- jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
-#define __mod_monitor_timer() mod_timer(&chan->monitor_timer, \
- jiffies + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO));
-#define __mod_ack_timer() mod_timer(&chan->ack_timer, \
- jiffies + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO));
+#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
+ L2CAP_DEFAULT_RETRANS_TO);
+#define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer)
+#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \
+ L2CAP_DEFAULT_MONITOR_TO);
+#define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer)
+#define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \
+ L2CAP_DEFAULT_ACK_TO);
+#define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer)
static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
{
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index c6d008d..3af8882 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -389,9 +389,9 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
if (chan->mode == L2CAP_MODE_ERTM) {
struct srej_list *l, *tmp;
- del_timer(&chan->retrans_timer);
- del_timer(&chan->monitor_timer);
- del_timer(&chan->ack_timer);
+ __clear_retrans_timer(chan);
+ __clear_monitor_timer(chan);
+ __clear_ack_timer(chan);
skb_queue_purge(&chan->srej_q);
skb_queue_purge(&chan->busy_q);
@@ -697,9 +697,9 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
sk = chan->sk;
if (chan->mode == L2CAP_MODE_ERTM) {
- del_timer(&chan->retrans_timer);
- del_timer(&chan->monitor_timer);
- del_timer(&chan->ack_timer);
+ __clear_retrans_timer(chan);
+ __clear_monitor_timer(chan);
+ __clear_ack_timer(chan);
}
req.dcid = cpu_to_le16(chan->dcid);
@@ -1177,7 +1177,7 @@ static void l2cap_monitor_timeout(unsigned long arg)
}
chan->retry_count++;
- __mod_monitor_timer();
+ __set_monitor_timer(chan);
l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
bh_unlock_sock(sk);
@@ -1192,7 +1192,7 @@ static void l2cap_retrans_timeout(unsigned long arg)
bh_lock_sock(sk);
chan->retry_count = 1;
- __mod_monitor_timer();
+ __set_monitor_timer(chan);
chan->conn_state |= L2CAP_CONN_WAIT_F;
@@ -1216,7 +1216,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
}
if (!chan->unacked_frames)
- del_timer(&chan->retrans_timer);
+ __clear_retrans_timer(chan);
}
void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
@@ -1343,7 +1343,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan)
l2cap_do_send(chan, tx_skb);
- __mod_retrans_timer();
+ __set_retrans_timer(chan);
bt_cb(skb)->tx_seq = chan->next_tx_seq;
chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
@@ -3260,8 +3260,8 @@ static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
l2cap_send_sframe(chan, control);
chan->retry_count = 1;
- del_timer(&chan->retrans_timer);
- __mod_monitor_timer();
+ __clear_retrans_timer(chan);
+ __set_monitor_timer(chan);
chan->conn_state |= L2CAP_CONN_WAIT_F;
@@ -3352,7 +3352,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c
chan->conn_state |= L2CAP_CONN_RNR_SENT;
- del_timer(&chan->ack_timer);
+ __clear_ack_timer(chan);
queue_work(_busy_wq, &chan->busy_work);
@@ -3521,9 +3521,9 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
if (L2CAP_CTRL_FINAL & rx_control &&
chan->conn_state & L2CAP_CONN_WAIT_F) {
- del_timer(&chan->monitor_timer);
+ __clear_monitor_timer(chan);
if (chan->unacked_frames > 0)
- __mod_retrans_timer();
+ __set_retrans_timer(chan);
chan->conn_state &= ~L2CAP_CONN_WAIT_F;
}
@@ -3604,7 +3604,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
l2cap_send_srejframe(chan, tx_seq);
- del_timer(&chan->ack_timer);
+ __clear_ack_timer(chan);
}
return 0;
@@ -3629,7 +3629,7 @@ expected:
l2cap_retransmit_frames(chan);
}
- __mod_ack_timer();
+ __set_ack_timer(chan);
chan->num_acked = (chan->num_acked + 1) % num_to_ack;
if (chan->num_acked == num_to_ack - 1)
@@ -3655,7 +3655,7 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co
if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
(chan->unacked_frames > 0))
- __mod_retrans_timer();
+ __set_retrans_timer(chan);
chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
l2cap_send_srejtail(chan);
@@ -3674,7 +3674,7 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co
} else {
if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
(chan->unacked_frames > 0))
- __mod_retrans_timer();
+ __set_retrans_timer(chan);
chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
if (chan->conn_state & L2CAP_CONN_SREJ_SENT)
@@ -3757,7 +3757,7 @@ static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_c
chan->conn_state |= L2CAP_CONN_SEND_FBIT;
if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) {
- del_timer(&chan->retrans_timer);
+ __clear_retrans_timer(chan);
if (rx_control & L2CAP_CTRL_POLL)
l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
return;
@@ -3775,9 +3775,9 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont
if (L2CAP_CTRL_FINAL & rx_control &&
chan->conn_state & L2CAP_CONN_WAIT_F) {
- del_timer(&chan->monitor_timer);
+ __clear_monitor_timer(chan);
if (chan->unacked_frames > 0)
- __mod_retrans_timer();
+ __set_retrans_timer(chan);
chan->conn_state &= ~L2CAP_CONN_WAIT_F;
}
--
1.7.5.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
end of thread, other threads:[~2011-06-08 15:18 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-06-08 15:18 [PATCH -v2 0/8] More l2cap rewrite Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 1/8] Bluetooth: Merge l2cap_chan_create() in the l2cap_sock_alloc() Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 2/8] Bluetooth: Add l2cap_chan_ops abstraction Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 3/8] Bluetooth: add recv() callback to l2cap_chan_ops Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 4/8] Bluetooth: add close() " Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 5/8] Bluetooth: Add state tracking to struct l2cap_chan Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 6/8] Bluetooth: Add refcnt " Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 7/8] Bluetooth: Make timer functions generic Gustavo F. Padovan
2011-06-08 15:18 ` [PATCH -v2 8/8] Bluetooth: keep reference if any ERTM timer is enabled Gustavo F. Padovan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox