#include <linux/crc16.h>
#include <net/sock.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
}
+static void l2cap_send_conn_req(struct l2cap_chan *chan)
+{
+ struct l2cap_conn *conn = chan->conn;
+ struct l2cap_conn_req req;
+
+ req.scid = cpu_to_le16(chan->scid);
+ req.psm = chan->psm;
+
+ chan->ident = l2cap_get_ident(conn);
+
+ set_bit(CONF_CONNECT_PEND, &chan->conf_state);
+
+ l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
+}
+
static void l2cap_do_start(struct l2cap_chan *chan)
{
struct l2cap_conn *conn = chan->conn;
return;
if (l2cap_chan_check_security(chan) &&
- __l2cap_no_conn_pending(chan)) {
- struct l2cap_conn_req req;
- req.scid = cpu_to_le16(chan->scid);
- req.psm = chan->psm;
-
- chan->ident = l2cap_get_ident(conn);
- set_bit(CONF_CONNECT_PEND, &chan->conf_state);
-
- l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
- sizeof(req), &req);
- }
+ __l2cap_no_conn_pending(chan))
+ l2cap_send_conn_req(chan);
} else {
struct l2cap_info_req req;
req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
conn->info_ident = l2cap_get_ident(conn);
- schedule_delayed_work(&conn->info_timer,
- msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
+ schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
l2cap_send_cmd(conn, conn->info_ident,
L2CAP_INFO_REQ, sizeof(req), &req);
}
if (chan->state == BT_CONNECT) {
- struct l2cap_conn_req req;
-
if (!l2cap_chan_check_security(chan) ||
!__l2cap_no_conn_pending(chan)) {
l2cap_chan_unlock(chan);
continue;
}
- req.scid = cpu_to_le16(chan->scid);
- req.psm = chan->psm;
-
- chan->ident = l2cap_get_ident(conn);
- set_bit(CONF_CONNECT_PEND, &chan->conf_state);
-
- l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
- sizeof(req), &req);
+ l2cap_send_conn_req(chan);
} else if (chan->state == BT_CONNECT2) {
struct l2cap_conn_rsp rsp;
if (chan->retry_count >= chan->remote_max_tx) {
l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
l2cap_chan_unlock(chan);
+ l2cap_chan_put(chan);
return;
}
l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
l2cap_chan_unlock(chan);
+ l2cap_chan_put(chan);
}
static void l2cap_retrans_timeout(struct work_struct *work)
l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
l2cap_chan_unlock(chan);
+ l2cap_chan_put(chan);
}
static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
l2cap_send_sframe(chan, control);
}
-static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct msghdr *msg, int len, int count, struct sk_buff *skb)
+static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
+ struct msghdr *msg, int len,
+ int count, struct sk_buff *skb)
{
struct l2cap_conn *conn = chan->conn;
struct sk_buff **frag;
count = min_t(unsigned int, conn->mtu, len);
*frag = chan->ops->alloc_skb(chan, count,
- msg->msg_flags & MSG_DONTWAIT, &err);
+ msg->msg_flags & MSG_DONTWAIT,
+ &err);
if (!*frag)
return err;
count = min_t(unsigned int, (conn->mtu - hlen), len);
skb = chan->ops->alloc_skb(chan, count + hlen,
- msg->msg_flags & MSG_DONTWAIT, &err);
+ msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb)
return ERR_PTR(err);
count = min_t(unsigned int, (conn->mtu - hlen), len);
skb = chan->ops->alloc_skb(chan, count + hlen,
- msg->msg_flags & MSG_DONTWAIT, &err);
+ msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb)
return ERR_PTR(err);
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
conn->info_ident = l2cap_get_ident(conn);
- schedule_delayed_work(&conn->info_timer,
- msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
+ schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
l2cap_send_cmd(conn, conn->info_ident,
L2CAP_INFO_REQ, sizeof(info), &info);
default:
l2cap_chan_set_err(chan, ECONNRESET);
- __set_chan_timer(chan,
- msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT));
+ __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
l2cap_send_disconn_req(conn, chan, ECONNRESET);
goto done;
}
return 0;
}
- if (type == L2CAP_IT_FEAT_MASK) {
+ switch (type) {
+ case L2CAP_IT_FEAT_MASK:
conn->feat_mask = get_unaligned_le32(rsp->data);
if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
l2cap_conn_start(conn);
}
- } else if (type == L2CAP_IT_FIXED_CHAN) {
+ break;
+
+ case L2CAP_IT_FIXED_CHAN:
+ conn->fixed_chan_mask = rsp->data[0];
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
conn->info_ident = 0;
l2cap_conn_start(conn);
+ break;
}
return 0;
if (!chan) {
BT_DBG("unknown cid 0x%4.4x", cid);
/* Drop packet and return */
- kfree(skb);
+ kfree_skb(skb);
return 0;
}
static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
{
- struct sock *sk = NULL;
struct l2cap_chan *chan;
chan = l2cap_global_chan_by_psm(0, psm, conn->src);
if (!chan)
goto drop;
- sk = chan->sk;
-
- lock_sock(sk);
-
- BT_DBG("sk %p, len %d", sk, skb->len);
+ BT_DBG("chan %p, len %d", chan, skb->len);
if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
goto drop;
goto drop;
if (!chan->ops->recv(chan->data, skb))
- goto done;
+ return 0;
drop:
kfree_skb(skb);
-done:
- if (sk)
- release_sock(sk);
return 0;
}
static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
{
- struct sock *sk = NULL;
struct l2cap_chan *chan;
chan = l2cap_global_chan_by_scid(0, cid, conn->src);
if (!chan)
goto drop;
- sk = chan->sk;
-
- lock_sock(sk);
-
- BT_DBG("sk %p, len %d", sk, skb->len);
+ BT_DBG("chan %p, len %d", chan, skb->len);
if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
goto drop;
goto drop;
if (!chan->ops->recv(chan->data, skb))
- goto done;
+ return 0;
drop:
kfree_skb(skb);
-done:
- if (sk)
- release_sock(sk);
return 0;
}
if (encrypt == 0x00) {
if (chan->sec_level == BT_SECURITY_MEDIUM) {
__clear_chan_timer(chan);
- __set_chan_timer(chan,
- msecs_to_jiffies(L2CAP_ENC_TIMEOUT));
+ __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
} else if (chan->sec_level == BT_SECURITY_HIGH)
l2cap_chan_close(chan, ECONNREFUSED);
} else {
if (!status && (chan->state == BT_CONNECTED ||
chan->state == BT_CONFIG)) {
+ struct sock *sk = chan->sk;
+
+ bt_sk(sk)->suspended = false;
+ sk->sk_state_change(sk);
+
l2cap_check_encryption(chan, encrypt);
l2cap_chan_unlock(chan);
continue;
if (chan->state == BT_CONNECT) {
if (!status) {
- struct l2cap_conn_req req;
- req.scid = cpu_to_le16(chan->scid);
- req.psm = chan->psm;
-
- chan->ident = l2cap_get_ident(conn);
- set_bit(CONF_CONNECT_PEND, &chan->conf_state);
-
- l2cap_send_cmd(conn, chan->ident,
- L2CAP_CONN_REQ, sizeof(req), &req);
+ l2cap_send_conn_req(chan);
} else {
__clear_chan_timer(chan);
- __set_chan_timer(chan,
- msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
+ __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
}
} else if (chan->state == BT_CONNECT2) {
struct sock *sk = chan->sk;
}
} else {
__l2cap_state_change(chan, BT_DISCONN);
- __set_chan_timer(chan,
- msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
+ __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
res = L2CAP_CR_SEC_BLOCK;
stat = L2CAP_CS_NO_INFO;
}