* [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