diff options
Diffstat (limited to 'net/bluetooth/l2cap_core.c')
-rw-r--r-- | net/bluetooth/l2cap_core.c | 1342 |
1 files changed, 858 insertions, 484 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 32d338c..24f144b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4,6 +4,7 @@ Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org> Copyright (C) 2010 Google Inc. Copyright (C) 2011 ProFUSION Embedded Systems + Copyright (c) 2012 Code Aurora Forum. All rights reserved. Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> @@ -49,7 +50,6 @@ #include <linux/crc16.h> #include <net/sock.h> -#include <asm/system.h> #include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> @@ -71,83 +71,56 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); static void l2cap_send_disconn_req(struct l2cap_conn *conn, - struct l2cap_chan *chan, int err); - -static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); + struct l2cap_chan *chan, int err); /* ---- L2CAP channels ---- */ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) { - struct l2cap_chan *c, *r = NULL; - - rcu_read_lock(); + struct l2cap_chan *c; - list_for_each_entry_rcu(c, &conn->chan_l, list) { - if (c->dcid == cid) { - r = c; - break; - } + list_for_each_entry(c, &conn->chan_l, list) { + if (c->dcid == cid) + return c; } - - rcu_read_unlock(); - return r; + return NULL; } static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) { - struct l2cap_chan *c, *r = NULL; - - rcu_read_lock(); + struct l2cap_chan *c; - list_for_each_entry_rcu(c, &conn->chan_l, list) { - if (c->scid == cid) { - r = c; - break; - } + list_for_each_entry(c, &conn->chan_l, list) { + if (c->scid == cid) + return c; } - - rcu_read_unlock(); - return r; + return NULL; } /* Find channel with given SCID. - * Returns locked socket */ + * Returns locked channel. */ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) { struct l2cap_chan *c; + mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_scid(conn, cid); if (c) - lock_sock(c->sk); + l2cap_chan_lock(c); + mutex_unlock(&conn->chan_lock); + return c; } static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) { - struct l2cap_chan *c, *r = NULL; - - rcu_read_lock(); - - list_for_each_entry_rcu(c, &conn->chan_l, list) { - if (c->ident == ident) { - r = c; - break; - } - } - - rcu_read_unlock(); - return r; -} - -static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) -{ struct l2cap_chan *c; - c = __l2cap_get_chan_by_ident(conn, ident); - if (c) - lock_sock(c->sk); - return c; + list_for_each_entry(c, &conn->chan_l, list) { + if (c->ident == ident) + return c; + } + return NULL; } static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src) @@ -217,51 +190,169 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) return 0; } -static char *state_to_string(int state) +static void __l2cap_state_change(struct l2cap_chan *chan, int state) { - switch(state) { - case BT_CONNECTED: - return "BT_CONNECTED"; - case BT_OPEN: - return "BT_OPEN"; - case BT_BOUND: - return "BT_BOUND"; - case BT_LISTEN: - return "BT_LISTEN"; - case BT_CONNECT: - return "BT_CONNECT"; - case BT_CONNECT2: - return "BT_CONNECT2"; - case BT_CONFIG: - return "BT_CONFIG"; - case BT_DISCONN: - return "BT_DISCONN"; - case BT_CLOSED: - return "BT_CLOSED"; - } + BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state), + state_to_string(state)); - return "invalid state"; + chan->state = state; + chan->ops->state_change(chan->data, state); } static void l2cap_state_change(struct l2cap_chan *chan, int state) { - BT_DBG("%p %s -> %s", chan, state_to_string(chan->state), - state_to_string(state)); + struct sock *sk = chan->sk; - chan->state = state; - chan->ops->state_change(chan->data, state); + lock_sock(sk); + __l2cap_state_change(chan, state); + release_sock(sk); +} + +static inline void __l2cap_chan_set_err(struct l2cap_chan *chan, int err) +{ + struct sock *sk = chan->sk; + + sk->sk_err = err; +} + +static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err) +{ + struct sock *sk = chan->sk; + + lock_sock(sk); + __l2cap_chan_set_err(chan, err); + release_sock(sk); +} + +/* ---- L2CAP sequence number lists ---- */ + +/* For ERTM, ordered lists of sequence numbers must be tracked for + * SREJ requests that are received and for frames that are to be + * retransmitted. These seq_list functions implement a singly-linked + * list in an array, where membership in the list can also be checked + * in constant time. Items can also be added to the tail of the list + * and removed from the head in constant time, without further memory + * allocs or frees. + */ + +static int l2cap_seq_list_init(struct l2cap_seq_list *seq_list, u16 size) +{ + size_t alloc_size, i; + + /* Allocated size is a power of 2 to map sequence numbers + * (which may be up to 14 bits) in to a smaller array that is + * sized for the negotiated ERTM transmit windows. + */ + alloc_size = roundup_pow_of_two(size); + + seq_list->list = kmalloc(sizeof(u16) * alloc_size, GFP_KERNEL); + if (!seq_list->list) + return -ENOMEM; + + seq_list->mask = alloc_size - 1; + seq_list->head = L2CAP_SEQ_LIST_CLEAR; + seq_list->tail = L2CAP_SEQ_LIST_CLEAR; + for (i = 0; i < alloc_size; i++) + seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR; + + return 0; +} + +static inline void l2cap_seq_list_free(struct l2cap_seq_list *seq_list) +{ + kfree(seq_list->list); +} + +static inline bool l2cap_seq_list_contains(struct l2cap_seq_list *seq_list, + u16 seq) +{ + /* Constant-time check for list membership */ + return seq_list->list[seq & seq_list->mask] != L2CAP_SEQ_LIST_CLEAR; +} + +static u16 l2cap_seq_list_remove(struct l2cap_seq_list *seq_list, u16 seq) +{ + u16 mask = seq_list->mask; + + if (seq_list->head == L2CAP_SEQ_LIST_CLEAR) { + /* In case someone tries to pop the head of an empty list */ + return L2CAP_SEQ_LIST_CLEAR; + } else if (seq_list->head == seq) { + /* Head can be removed in constant time */ + seq_list->head = seq_list->list[seq & mask]; + seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; + + if (seq_list->head == L2CAP_SEQ_LIST_TAIL) { + seq_list->head = L2CAP_SEQ_LIST_CLEAR; + seq_list->tail = L2CAP_SEQ_LIST_CLEAR; + } + } else { + /* Walk the list to find the sequence number */ + u16 prev = seq_list->head; + while (seq_list->list[prev & mask] != seq) { + prev = seq_list->list[prev & mask]; + if (prev == L2CAP_SEQ_LIST_TAIL) + return L2CAP_SEQ_LIST_CLEAR; + } + + /* Unlink the number from the list and clear it */ + seq_list->list[prev & mask] = seq_list->list[seq & mask]; + seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; + if (seq_list->tail == seq) + seq_list->tail = prev; + } + return seq; +} + +static inline u16 l2cap_seq_list_pop(struct l2cap_seq_list *seq_list) +{ + /* Remove the head in constant time */ + return l2cap_seq_list_remove(seq_list, seq_list->head); +} + +static void l2cap_seq_list_clear(struct l2cap_seq_list *seq_list) +{ + u16 i; + + if (seq_list->head == L2CAP_SEQ_LIST_CLEAR) + return; + + for (i = 0; i <= seq_list->mask; i++) + seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR; + + seq_list->head = L2CAP_SEQ_LIST_CLEAR; + seq_list->tail = L2CAP_SEQ_LIST_CLEAR; +} + +static void l2cap_seq_list_append(struct l2cap_seq_list *seq_list, u16 seq) +{ + u16 mask = seq_list->mask; + + /* All appends happen in constant time */ + + if (seq_list->list[seq & mask] != L2CAP_SEQ_LIST_CLEAR) + return; + + if (seq_list->tail == L2CAP_SEQ_LIST_CLEAR) + seq_list->head = seq; + else + seq_list->list[seq_list->tail & mask] = seq; + + seq_list->tail = seq; + seq_list->list[seq & mask] = L2CAP_SEQ_LIST_TAIL; } static void l2cap_chan_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, chan_timer.work); - struct sock *sk = chan->sk; + struct l2cap_conn *conn = chan->conn; int reason; - BT_DBG("chan %p state %d", chan, chan->state); + BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); - lock_sock(sk); + mutex_lock(&conn->chan_lock); + l2cap_chan_lock(chan); if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG) reason = ECONNREFUSED; @@ -273,13 +364,15 @@ static void l2cap_chan_timeout(struct work_struct *work) l2cap_chan_close(chan, reason); - release_sock(sk); + l2cap_chan_unlock(chan); chan->ops->close(chan->data); + mutex_unlock(&conn->chan_lock); + l2cap_chan_put(chan); } -struct l2cap_chan *l2cap_chan_create(struct sock *sk) +struct l2cap_chan *l2cap_chan_create(void) { struct l2cap_chan *chan; @@ -287,7 +380,7 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk) if (!chan) return NULL; - chan->sk = sk; + mutex_init(&chan->lock); write_lock(&chan_list_lock); list_add(&chan->global_l, &chan_list); @@ -299,7 +392,7 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk) atomic_set(&chan->refcnt, 1); - BT_DBG("sk %p chan %p", sk, chan); + BT_DBG("chan %p", chan); return chan; } @@ -313,16 +406,28 @@ void l2cap_chan_destroy(struct l2cap_chan *chan) l2cap_chan_put(chan); } -static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) +void l2cap_chan_set_defaults(struct l2cap_chan *chan) +{ + chan->fcs = L2CAP_FCS_CRC16; + chan->max_tx = L2CAP_DEFAULT_MAX_TX; + chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; + chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; + chan->sec_level = BT_SECURITY_LOW; + + set_bit(FLAG_FORCE_ACTIVE, &chan->flags); +} + +static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, - chan->psm, chan->dcid); + __le16_to_cpu(chan->psm), chan->dcid); conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; chan->conn = conn; - if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) { + switch (chan->chan_type) { + case L2CAP_CHAN_CONN_ORIENTED: if (conn->hcon->type == LE_LINK) { /* LE connection */ chan->omtu = L2CAP_LE_DEFAULT_MTU; @@ -333,12 +438,16 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) chan->scid = l2cap_alloc_cid(conn); chan->omtu = L2CAP_DEFAULT_MTU; } - } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) { + break; + + case L2CAP_CHAN_CONN_LESS: /* Connectionless socket */ chan->scid = L2CAP_CID_CONN_LESS; chan->dcid = L2CAP_CID_CONN_LESS; chan->omtu = L2CAP_DEFAULT_MTU; - } else { + break; + + default: /* Raw socket can send/recv signalling messages only */ chan->scid = L2CAP_CID_SIGNALING; chan->dcid = L2CAP_CID_SIGNALING; @@ -354,11 +463,16 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) l2cap_chan_hold(chan); - list_add_rcu(&chan->list, &conn->chan_l); + list_add(&chan->list, &conn->chan_l); +} + +static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) +{ + mutex_lock(&conn->chan_lock); + __l2cap_chan_add(conn, chan); + mutex_unlock(&conn->chan_lock); } -/* Delete channel. - * Must be called on the locked socket. */ static void l2cap_chan_del(struct l2cap_chan *chan, int err) { struct sock *sk = chan->sk; @@ -371,8 +485,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) if (conn) { /* Delete from channel list */ - list_del_rcu(&chan->list); - synchronize_rcu(); + list_del(&chan->list); l2cap_chan_put(chan); @@ -380,11 +493,13 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) hci_conn_put(conn->hcon); } - l2cap_state_change(chan, BT_CLOSED); + lock_sock(sk); + + __l2cap_state_change(chan, BT_CLOSED); sock_set_flag(sk, SOCK_ZAPPED); if (err) - sk->sk_err = err; + __l2cap_chan_set_err(chan, err); if (parent) { bt_accept_unlink(sk); @@ -392,6 +507,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) } else sk->sk_state_change(sk); + release_sock(sk); + if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) && test_bit(CONF_INPUT_DONE, &chan->conf_state))) return; @@ -407,6 +524,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) skb_queue_purge(&chan->srej_q); + l2cap_seq_list_free(&chan->srej_list); + l2cap_seq_list_free(&chan->retrans_list); list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { list_del(&l->list); kfree(l); @@ -423,10 +542,12 @@ 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_lock(chan); __clear_chan_timer(chan); - lock_sock(sk); l2cap_chan_close(chan, ECONNRESET); - release_sock(sk); + l2cap_chan_unlock(chan); + chan->ops->close(chan->data); } } @@ -436,21 +557,23 @@ 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, chan->state, sk->sk_socket); + BT_DBG("chan %p state %s sk %p", chan, + state_to_string(chan->state), sk); switch (chan->state) { case BT_LISTEN: + lock_sock(sk); l2cap_chan_cleanup_listen(sk); - l2cap_state_change(chan, BT_CLOSED); + __l2cap_state_change(chan, BT_CLOSED); sock_set_flag(sk, SOCK_ZAPPED); + release_sock(sk); break; case BT_CONNECTED: case BT_CONFIG: if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && conn->hcon->type == ACL_LINK) { - __clear_chan_timer(chan); __set_chan_timer(chan, sk->sk_sndtimeo); l2cap_send_disconn_req(conn, chan, reason); } else @@ -463,7 +586,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) struct l2cap_conn_rsp rsp; __u16 result; - if (bt_sk(sk)->defer_setup) + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) result = L2CAP_CR_SEC_BLOCK; else result = L2CAP_CR_BAD_PSM; @@ -486,7 +609,9 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) break; default: + lock_sock(sk); sock_set_flag(sk, SOCK_ZAPPED); + release_sock(sk); break; } } @@ -594,6 +719,117 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) hci_send_acl(chan->conn->hchan, skb, flags); } +static void __unpack_enhanced_control(u16 enh, struct l2cap_ctrl *control) +{ + control->reqseq = (enh & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT; + control->final = (enh & L2CAP_CTRL_FINAL) >> L2CAP_CTRL_FINAL_SHIFT; + + if (enh & L2CAP_CTRL_FRAME_TYPE) { + /* S-Frame */ + control->sframe = 1; + control->poll = (enh & L2CAP_CTRL_POLL) >> L2CAP_CTRL_POLL_SHIFT; + control->super = (enh & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT; + + control->sar = 0; + control->txseq = 0; + } else { + /* I-Frame */ + control->sframe = 0; + control->sar = (enh & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT; + control->txseq = (enh & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT; + + control->poll = 0; + control->super = 0; + } +} + +static void __unpack_extended_control(u32 ext, struct l2cap_ctrl *control) +{ + control->reqseq = (ext & L2CAP_EXT_CTRL_REQSEQ) >> L2CAP_EXT_CTRL_REQSEQ_SHIFT; + control->final = (ext & L2CAP_EXT_CTRL_FINAL) >> L2CAP_EXT_CTRL_FINAL_SHIFT; + + if (ext & L2CAP_EXT_CTRL_FRAME_TYPE) { + /* S-Frame */ + control->sframe = 1; + control->poll = (ext & L2CAP_EXT_CTRL_POLL) >> L2CAP_EXT_CTRL_POLL_SHIFT; + control->super = (ext & L2CAP_EXT_CTRL_SUPERVISE) >> L2CAP_EXT_CTRL_SUPER_SHIFT; + + control->sar = 0; + control->txseq = 0; + } else { + /* I-Frame */ + control->sframe = 0; + control->sar = (ext & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT; + control->txseq = (ext & L2CAP_EXT_CTRL_TXSEQ) >> L2CAP_EXT_CTRL_TXSEQ_SHIFT; + + control->poll = 0; + control->super = 0; + } +} + +static inline void __unpack_control(struct l2cap_chan *chan, + struct sk_buff *skb) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) { + __unpack_extended_control(get_unaligned_le32(skb->data), + &bt_cb(skb)->control); + } else { + __unpack_enhanced_control(get_unaligned_le16(skb->data), + &bt_cb(skb)->control); + } +} + +static u32 __pack_extended_control(struct l2cap_ctrl *control) +{ + u32 packed; + + packed = control->reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT; + packed |= control->final << L2CAP_EXT_CTRL_FINAL_SHIFT; + + if (control->sframe) { + packed |= control->poll << L2CAP_EXT_CTRL_POLL_SHIFT; + packed |= control->super << L2CAP_EXT_CTRL_SUPER_SHIFT; + packed |= L2CAP_EXT_CTRL_FRAME_TYPE; + } else { + packed |= control->sar << L2CAP_EXT_CTRL_SAR_SHIFT; + packed |= control->txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT; + } + + return packed; +} + +static u16 __pack_enhanced_control(struct l2cap_ctrl *control) +{ + u16 packed; + + packed = control->reqseq << L2CAP_CTRL_REQSEQ_SHIFT; + packed |= control->final << L2CAP_CTRL_FINAL_SHIFT; + + if (control->sframe) { + packed |= control->poll << L2CAP_CTRL_POLL_SHIFT; + packed |= control->super << L2CAP_CTRL_SUPER_SHIFT; + packed |= L2CAP_CTRL_FRAME_TYPE; + } else { + packed |= control->sar << L2CAP_CTRL_SAR_SHIFT; + packed |= control->txseq << L2CAP_CTRL_TXSEQ_SHIFT; + } + + return packed; +} + +static inline void __pack_control(struct l2cap_chan *chan, + struct l2cap_ctrl *control, + struct sk_buff *skb) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) { + put_unaligned_le32(__pack_extended_control(control), + skb->data + L2CAP_HDR_SIZE); + } else { + put_unaligned_le16(__pack_enhanced_control(control), + skb->data + L2CAP_HDR_SIZE); + } +} + static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control) { struct sk_buff *skb; @@ -661,26 +897,60 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) 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_chan_ready(struct l2cap_chan *chan) +{ + struct sock *sk = chan->sk; + struct sock *parent; + + lock_sock(sk); + + parent = bt_sk(sk)->parent; + + BT_DBG("sk %p, parent %p", sk, parent); + + chan->conf_state = 0; + __clear_chan_timer(chan); + + __l2cap_state_change(chan, BT_CONNECTED); + sk->sk_state_change(sk); + + if (parent) + parent->sk_data_ready(parent, 0); + + release_sock(sk); +} + static void l2cap_do_start(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; + if (conn->hcon->type == LE_LINK) { + l2cap_chan_ready(chan); + return; + } + if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) 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); @@ -688,8 +958,7 @@ static void l2cap_do_start(struct l2cap_chan *chan) 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); @@ -714,14 +983,12 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask) static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err) { - struct sock *sk; + struct sock *sk = chan->sk; struct l2cap_disconn_req req; if (!conn) return; - sk = chan->sk; - if (chan->mode == L2CAP_MODE_ERTM) { __clear_retrans_timer(chan); __clear_monitor_timer(chan); @@ -733,56 +1000,47 @@ 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); - l2cap_state_change(chan, BT_DISCONN); - sk->sk_err = err; + lock_sock(sk); + __l2cap_state_change(chan, BT_DISCONN); + __l2cap_chan_set_err(chan, err); + release_sock(sk); } /* ---- L2CAP connections ---- */ static void l2cap_conn_start(struct l2cap_conn *conn) { - struct l2cap_chan *chan; + struct l2cap_chan *chan, *tmp; BT_DBG("conn %p", conn); - rcu_read_lock(); + mutex_lock(&conn->chan_lock); - list_for_each_entry_rcu(chan, &conn->chan_l, list) { + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { struct sock *sk = chan->sk; - bh_lock_sock(sk); + l2cap_chan_lock(chan); if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } if (chan->state == BT_CONNECT) { - struct l2cap_conn_req req; - if (!l2cap_chan_check_security(chan) || !__l2cap_no_conn_pending(chan)) { - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } if (!l2cap_mode_supported(chan->mode, conn->feat_mask) && test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) { - /* l2cap_chan_close() calls list_del(chan) - * so release the lock */ l2cap_chan_close(chan, ECONNRESET); - bh_unlock_sock(sk); + 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; @@ -791,7 +1049,9 @@ static void l2cap_conn_start(struct l2cap_conn *conn) rsp.dcid = cpu_to_le16(chan->scid); if (l2cap_chan_check_security(chan)) { - if (bt_sk(sk)->defer_setup) { + lock_sock(sk); + if (test_bit(BT_SK_DEFER_SETUP, + &bt_sk(sk)->flags)) { struct sock *parent = bt_sk(sk)->parent; rsp.result = cpu_to_le16(L2CAP_CR_PEND); rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); @@ -799,10 +1059,11 @@ static void l2cap_conn_start(struct l2cap_conn *conn) parent->sk_data_ready(parent, 0); } else { - l2cap_state_change(chan, 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); } + release_sock(sk); } else { rsp.result = cpu_to_le16(L2CAP_CR_PEND); rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND); @@ -813,7 +1074,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (test_bit(CONF_REQ_SENT, &chan->conf_state) || rsp.result != L2CAP_CR_SUCCESS) { - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } @@ -823,16 +1084,18 @@ static void l2cap_conn_start(struct l2cap_conn *conn) chan->num_conf_req++; } - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); } - rcu_read_unlock(); + mutex_unlock(&conn->chan_lock); } -/* Find socket with cid and source bdaddr. +/* Find socket with cid and source/destination bdaddr. * Returns closest match, locked. */ -static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src) +static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid, + bdaddr_t *src, + bdaddr_t *dst) { struct l2cap_chan *c, *c1 = NULL; @@ -845,14 +1108,22 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdadd continue; if (c->scid == cid) { + int src_match, dst_match; + int src_any, dst_any; + /* Exact match. */ - if (!bacmp(&bt_sk(sk)->src, src)) { + src_match = !bacmp(&bt_sk(sk)->src, src); + dst_match = !bacmp(&bt_sk(sk)->dst, dst); + if (src_match && dst_match) { read_unlock(&chan_list_lock); return c; } /* Closest match */ - if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) + src_any = !bacmp(&bt_sk(sk)->src, BDADDR_ANY); + dst_any = !bacmp(&bt_sk(sk)->dst, BDADDR_ANY); + if ((src_match && dst_any) || (src_any && dst_match) || + (src_any && dst_any)) c1 = c; } } @@ -871,7 +1142,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) /* Check if we have socket listening on cid */ pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA, - conn->src); + conn->src, conn->dst); if (!pchan) return; @@ -902,30 +1173,13 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) __set_chan_timer(chan, sk->sk_sndtimeo); - l2cap_state_change(chan, BT_CONNECTED); + __l2cap_state_change(chan, BT_CONNECTED); parent->sk_data_ready(parent, 0); clean: release_sock(parent); } -static void l2cap_chan_ready(struct sock *sk) -{ - struct l2cap_chan *chan = l2cap_pi(sk)->chan; - struct sock *parent = bt_sk(sk)->parent; - - BT_DBG("sk %p, parent %p", sk, parent); - - chan->conf_state = 0; - __clear_chan_timer(chan); - - l2cap_state_change(chan, BT_CONNECTED); - sk->sk_state_change(sk); - - if (parent) - parent->sk_data_ready(parent, 0); -} - static void l2cap_conn_ready(struct l2cap_conn *conn) { struct l2cap_chan *chan; @@ -938,29 +1192,31 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) if (conn->hcon->out && conn->hcon->type == LE_LINK) smp_conn_security(conn, conn->hcon->pending_sec_level); - rcu_read_lock(); + mutex_lock(&conn->chan_lock); - list_for_each_entry_rcu(chan, &conn->chan_l, list) { - struct sock *sk = chan->sk; + list_for_each_entry(chan, &conn->chan_l, list) { - bh_lock_sock(sk); + l2cap_chan_lock(chan); if (conn->hcon->type == LE_LINK) { if (smp_conn_security(conn, chan->sec_level)) - l2cap_chan_ready(sk); + l2cap_chan_ready(chan); } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { + struct sock *sk = chan->sk; __clear_chan_timer(chan); - l2cap_state_change(chan, BT_CONNECTED); + lock_sock(sk); + __l2cap_state_change(chan, BT_CONNECTED); sk->sk_state_change(sk); + release_sock(sk); } else if (chan->state == BT_CONNECT) l2cap_do_start(chan); - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); } - rcu_read_unlock(); + mutex_unlock(&conn->chan_lock); } /* Notify sockets that we cannot guaranty reliability anymore */ @@ -970,16 +1226,14 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) BT_DBG("conn %p", conn); - rcu_read_lock(); - - list_for_each_entry_rcu(chan, &conn->chan_l, list) { - struct sock *sk = chan->sk; + mutex_lock(&conn->chan_lock); + list_for_each_entry(chan, &conn->chan_l, list) { if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) - sk->sk_err = err; + __l2cap_chan_set_err(chan, err); } - rcu_read_unlock(); + mutex_unlock(&conn->chan_lock); } static void l2cap_info_timeout(struct work_struct *work) @@ -997,7 +1251,6 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) { struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_chan *chan, *l; - struct sock *sk; if (!conn) return; @@ -1006,21 +1259,29 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) kfree_skb(conn->rx_skb); + mutex_lock(&conn->chan_lock); + /* Kill channels */ list_for_each_entry_safe(chan, l, &conn->chan_l, list) { - sk = chan->sk; - lock_sock(sk); + l2cap_chan_hold(chan); + l2cap_chan_lock(chan); + l2cap_chan_del(chan, err); - release_sock(sk); + + l2cap_chan_unlock(chan); + chan->ops->close(chan->data); + l2cap_chan_put(chan); } + mutex_unlock(&conn->chan_lock); + hci_chan_del(conn->hchan); if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) cancel_delayed_work_sync(&conn->info_timer); - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) { + if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) { cancel_delayed_work_sync(&conn->security_timer); smp_chan_destroy(conn); } @@ -1072,6 +1333,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) conn->feat_mask = 0; spin_lock_init(&conn->lock); + mutex_init(&conn->chan_lock); INIT_LIST_HEAD(&conn->chan_l); @@ -1087,10 +1349,12 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) /* ---- Socket interface ---- */ -/* Find socket with psm and source bdaddr. +/* Find socket with psm and source / destination bdaddr. * Returns closest match. */ -static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src) +static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, + bdaddr_t *src, + bdaddr_t *dst) { struct l2cap_chan *c, *c1 = NULL; @@ -1103,14 +1367,22 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr continue; if (c->psm == psm) { + int src_match, dst_match; + int src_any, dst_any; + /* Exact match. */ - if (!bacmp(&bt_sk(sk)->src, src)) { + src_match = !bacmp(&bt_sk(sk)->src, src); + dst_match = !bacmp(&bt_sk(sk)->dst, dst); + if (src_match && dst_match) { read_unlock(&chan_list_lock); return c; } /* Closest match */ - if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) + src_any = !bacmp(&bt_sk(sk)->src, BDADDR_ANY); + dst_any = !bacmp(&bt_sk(sk)->dst, BDADDR_ANY); + if ((src_match && dst_any) || (src_any && dst_match) || + (src_any && dst_any)) c1 = c; } } @@ -1120,7 +1392,8 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr return c1; } -int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst) +int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, + bdaddr_t *dst, u8 dst_type) { struct sock *sk = chan->sk; bdaddr_t *src = &bt_sk(sk)->src; @@ -1130,8 +1403,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d __u8 auth_type; int err; - BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), - chan->psm); + BT_DBG("%s -> %s (type %u) psm 0x%2.2x", batostr(src), batostr(dst), + dst_type, __le16_to_cpu(chan->psm)); hdev = hci_get_route(dst, src); if (!hdev) @@ -1139,7 +1412,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d hci_dev_lock(hdev); - lock_sock(sk); + l2cap_chan_lock(chan); /* PSM must be odd and lsb of upper byte must be 0 */ if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid && @@ -1166,17 +1439,21 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d goto done; } + lock_sock(sk); + switch (sk->sk_state) { case BT_CONNECT: case BT_CONNECT2: case BT_CONFIG: /* Already connecting */ err = 0; + release_sock(sk); goto done; case BT_CONNECTED: /* Already connected */ err = -EISCONN; + release_sock(sk); goto done; case BT_OPEN: @@ -1186,22 +1463,26 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d default: err = -EBADFD; + release_sock(sk); goto done; } /* Set destination address and psm */ bacpy(&bt_sk(sk)->dst, dst); + + release_sock(sk); + chan->psm = psm; chan->dcid = cid; auth_type = l2cap_get_auth_type(chan); if (chan->dcid == L2CAP_CID_LE_DATA) - hcon = hci_connect(hdev, LE_LINK, dst, - chan->sec_level, auth_type); + hcon = hci_connect(hdev, LE_LINK, dst, dst_type, + chan->sec_level, auth_type); else - hcon = hci_connect(hdev, ACL_LINK, dst, - chan->sec_level, auth_type); + hcon = hci_connect(hdev, ACL_LINK, dst, dst_type, + chan->sec_level, auth_type); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); @@ -1215,10 +1496,24 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d goto done; } + if (hcon->type == LE_LINK) { + err = 0; + + if (!list_empty(&conn->chan_l)) { + err = -EBUSY; + hci_conn_put(hcon); + } + + if (err) + goto done; + } + /* Update source addr of the socket */ bacpy(src, conn->src); + l2cap_chan_unlock(chan); l2cap_chan_add(conn, chan); + l2cap_chan_lock(chan); l2cap_state_change(chan, BT_CONNECT); __set_chan_timer(chan, sk->sk_sndtimeo); @@ -1235,6 +1530,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d err = 0; done: + l2cap_chan_unlock(chan); hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1276,14 +1572,15 @@ static void l2cap_monitor_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, monitor_timer.work); - struct sock *sk = chan->sk; BT_DBG("chan %p", chan); - lock_sock(sk); + l2cap_chan_lock(chan); + if (chan->retry_count >= chan->remote_max_tx) { l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); - release_sock(sk); + l2cap_chan_unlock(chan); + l2cap_chan_put(chan); return; } @@ -1291,25 +1588,28 @@ static void l2cap_monitor_timeout(struct work_struct *work) __set_monitor_timer(chan); l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); - release_sock(sk); + l2cap_chan_unlock(chan); + l2cap_chan_put(chan); } static void l2cap_retrans_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, retrans_timer.work); - struct sock *sk = chan->sk; BT_DBG("chan %p", chan); - lock_sock(sk); + l2cap_chan_lock(chan); + chan->retry_count = 1; __set_monitor_timer(chan); set_bit(CONN_WAIT_F, &chan->conn_state); l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); - release_sock(sk); + + l2cap_chan_unlock(chan); + l2cap_chan_put(chan); } static void l2cap_drop_acked_frames(struct l2cap_chan *chan) @@ -1318,7 +1618,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) while ((skb = skb_peek(&chan->tx_q)) && chan->unacked_frames) { - if (bt_cb(skb)->tx_seq == chan->expected_ack_seq) + if (bt_cb(skb)->control.txseq == chan->expected_ack_seq) break; skb = skb_dequeue(&chan->tx_q); @@ -1340,6 +1640,7 @@ static void l2cap_streaming_send(struct l2cap_chan *chan) while ((skb = skb_dequeue(&chan->tx_q))) { control = __get_control(chan, skb->data + L2CAP_HDR_SIZE); control |= __set_txseq(chan, chan->next_tx_seq); + control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar); __put_control(chan, control, skb->data + L2CAP_HDR_SIZE); if (chan->fcs == L2CAP_FCS_CRC16) { @@ -1365,21 +1666,21 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq) if (!skb) return; - while (bt_cb(skb)->tx_seq != tx_seq) { + while (bt_cb(skb)->control.txseq != tx_seq) { if (skb_queue_is_last(&chan->tx_q, skb)) return; skb = skb_queue_next(&chan->tx_q, skb); } - if (chan->remote_max_tx && - bt_cb(skb)->retries == chan->remote_max_tx) { + if (bt_cb(skb)->control.retries == chan->remote_max_tx && + chan->remote_max_tx) { l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); return; } tx_skb = skb_clone(skb, GFP_ATOMIC); - bt_cb(skb)->retries++; + bt_cb(skb)->control.retries++; control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE); control &= __get_sar_mask(chan); @@ -1412,17 +1713,20 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) if (chan->state != BT_CONNECTED) return -ENOTCONN; + if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) + return 0; + while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) { - if (chan->remote_max_tx && - bt_cb(skb)->retries == chan->remote_max_tx) { + if (bt_cb(skb)->control.retries == chan->remote_max_tx && + chan->remote_max_tx) { l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); break; } tx_skb = skb_clone(skb, GFP_ATOMIC); - bt_cb(skb)->retries++; + bt_cb(skb)->control.retries++; control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE); control &= __get_sar_mask(chan); @@ -1432,6 +1736,7 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) control |= __set_reqseq(chan, chan->buffer_seq); control |= __set_txseq(chan, chan->next_tx_seq); + control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar); __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE); @@ -1446,21 +1751,23 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) __set_retrans_timer(chan); - bt_cb(skb)->tx_seq = chan->next_tx_seq; + bt_cb(skb)->control.txseq = chan->next_tx_seq; chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq); - if (bt_cb(skb)->retries == 1) + if (bt_cb(skb)->control.retries == 1) { chan->unacked_frames++; + if (!nsent++) + __clear_ack_timer(chan); + } + chan->frames_sent++; if (skb_queue_is_last(&chan->tx_q, skb)) chan->tx_send_head = NULL; else chan->tx_send_head = skb_queue_next(&chan->tx_q, skb); - - nsent++; } return nsent; @@ -1478,7 +1785,7 @@ static int l2cap_retransmit_frames(struct l2cap_chan *chan) return ret; } -static void l2cap_send_ack(struct l2cap_chan *chan) +static void __l2cap_send_ack(struct l2cap_chan *chan) { u32 control = 0; @@ -1498,6 +1805,12 @@ static void l2cap_send_ack(struct l2cap_chan *chan) l2cap_send_sframe(chan, control); } +static void l2cap_send_ack(struct l2cap_chan *chan) +{ + __clear_ack_timer(chan); + __l2cap_send_ack(chan); +} + static void l2cap_send_srejtail(struct l2cap_chan *chan) { struct srej_list *tail; @@ -1512,11 +1825,13 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan) l2cap_send_sframe(chan, control); } -static inline int l2cap_skbuff_fromiovec(struct sock *sk, 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 = l2cap_pi(sk)->chan->conn; + struct l2cap_conn *conn = chan->conn; struct sk_buff **frag; - int err, sent = 0; + int sent = 0; if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) return -EFAULT; @@ -1527,11 +1842,17 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in /* Continuation fragments (no L2CAP header) */ frag = &skb_shinfo(skb)->frag_list; while (len) { + struct sk_buff *tmp; + count = min_t(unsigned int, conn->mtu, len); - *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err); - if (!*frag) - return err; + tmp = chan->ops->alloc_skb(chan, count, + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + + *frag = tmp; + if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) return -EFAULT; @@ -1540,6 +1861,9 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in sent += count; len -= count; + skb->len += (*frag)->len; + skb->data_len += (*frag)->len; + frag = &(*frag)->next; } @@ -1550,29 +1874,29 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority) { - struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE; struct l2cap_hdr *lh; - BT_DBG("sk %p len %d priority %u", sk, (int)len, priority); + BT_DBG("chan %p len %d priority %u", chan, (int)len, priority); count = min_t(unsigned int, (conn->mtu - hlen), len); - skb = bt_skb_send_alloc(sk, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); - if (!skb) - return ERR_PTR(err); + + skb = chan->ops->alloc_skb(chan, count + hlen, + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(skb)) + return skb; skb->priority = priority; /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(chan->dcid); - lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); - put_unaligned_le16(chan->psm, skb_put(skb, 2)); + lh->len = cpu_to_le16(len + L2CAP_PSMLEN_SIZE); + put_unaligned(chan->psm, skb_put(skb, L2CAP_PSMLEN_SIZE)); - err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); if (unlikely(err < 0)) { kfree_skb(skb); return ERR_PTR(err); @@ -1584,28 +1908,28 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority) { - struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; - int err, count, hlen = L2CAP_HDR_SIZE; + int err, count; struct l2cap_hdr *lh; - BT_DBG("sk %p len %d", sk, (int)len); + BT_DBG("chan %p len %d", chan, (int)len); - count = min_t(unsigned int, (conn->mtu - hlen), len); - skb = bt_skb_send_alloc(sk, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); - if (!skb) - return ERR_PTR(err); + count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len); + + skb = chan->ops->alloc_skb(chan, count + L2CAP_HDR_SIZE, + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(skb)) + return skb; skb->priority = priority; /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(chan->dcid); - lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); + lh->len = cpu_to_le16(len); - err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); if (unlikely(err < 0)) { kfree_skb(skb); return ERR_PTR(err); @@ -1615,15 +1939,14 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, - u32 control, u16 sdulen) + u16 sdulen) { - struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen; struct l2cap_hdr *lh; - BT_DBG("sk %p len %d", sk, (int)len); + BT_DBG("chan %p len %d", chan, (int)len); if (!conn) return ERR_PTR(-ENOTCONN); @@ -1640,22 +1963,23 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, hlen += L2CAP_FCS_SIZE; count = min_t(unsigned int, (conn->mtu - hlen), len); - skb = bt_skb_send_alloc(sk, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); - if (!skb) - return ERR_PTR(err); + + skb = chan->ops->alloc_skb(chan, count + hlen, + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(skb)) + return skb; /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); - __put_control(chan, control, skb_put(skb, __ctrl_size(chan))); + __put_control(chan, 0, skb_put(skb, __ctrl_size(chan))); if (sdulen) put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE)); - err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); if (unlikely(err < 0)) { kfree_skb(skb); return ERR_PTR(err); @@ -1664,61 +1988,82 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, if (chan->fcs == L2CAP_FCS_CRC16) put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE)); - bt_cb(skb)->retries = 0; + bt_cb(skb)->control.retries = 0; return skb; } -static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) +static int l2cap_segment_sdu(struct l2cap_chan *chan, + struct sk_buff_head *seg_queue, + struct msghdr *msg, size_t len) { struct sk_buff *skb; - struct sk_buff_head sar_queue; - u32 control; - size_t size = 0; + u16 sdu_len; + size_t pdu_len; + int err = 0; + u8 sar; - skb_queue_head_init(&sar_queue); - control = __set_ctrl_sar(chan, L2CAP_SAR_START); - skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len); - if (IS_ERR(skb)) - return PTR_ERR(skb); + BT_DBG("chan %p, msg %p, len %d", chan, msg, (int)len); + + /* It is critical that ERTM PDUs fit in a single HCI fragment, + * so fragmented skbs are not used. The HCI layer's handling + * of fragmented skbs is not compatible with ERTM's queueing. + */ - __skb_queue_tail(&sar_queue, skb); - len -= chan->remote_mps; - size += chan->remote_mps; + /* PDU size is derived from the HCI MTU */ + pdu_len = chan->conn->mtu; - while (len > 0) { - size_t buflen; + pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD); - if (len > chan->remote_mps) { - control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE); - buflen = chan->remote_mps; - } else { - control = __set_ctrl_sar(chan, L2CAP_SAR_END); - buflen = len; - } + /* Adjust for largest possible L2CAP overhead. */ + pdu_len -= L2CAP_EXT_HDR_SIZE + L2CAP_FCS_SIZE; + + /* Remote device may have requested smaller PDUs */ + pdu_len = min_t(size_t, pdu_len, chan->remote_mps); + + if (len <= pdu_len) { + sar = L2CAP_SAR_UNSEGMENTED; + sdu_len = 0; + pdu_len = len; + } else { + sar = L2CAP_SAR_START; + sdu_len = len; + pdu_len -= L2CAP_SDULEN_SIZE; + } + + while (len > 0) { + skb = l2cap_create_iframe_pdu(chan, msg, pdu_len, sdu_len); - skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0); if (IS_ERR(skb)) { - skb_queue_purge(&sar_queue); + __skb_queue_purge(seg_queue); return PTR_ERR(skb); } - __skb_queue_tail(&sar_queue, skb); - len -= buflen; - size += buflen; + bt_cb(skb)->control.sar = sar; + __skb_queue_tail(seg_queue, skb); + + len -= pdu_len; + if (sdu_len) { + sdu_len = 0; + pdu_len += L2CAP_SDULEN_SIZE; + } + + if (len <= pdu_len) { + sar = L2CAP_SAR_END; + pdu_len = len; + } else { + sar = L2CAP_SAR_CONTINUE; + } } - skb_queue_splice_tail(&sar_queue, &chan->tx_q); - if (chan->tx_send_head == NULL) - chan->tx_send_head = sar_queue.next; - return size; + return err; } int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority) { struct sk_buff *skb; - u32 control; int err; + struct sk_buff_head seg_queue; /* Connectionless channel */ if (chan->chan_type == L2CAP_CHAN_CONN_LESS) { @@ -1747,42 +2092,47 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: - /* Entire SDU fits into one PDU */ - if (len <= chan->remote_mps) { - control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED); - skb = l2cap_create_iframe_pdu(chan, msg, len, control, - 0); - if (IS_ERR(skb)) - return PTR_ERR(skb); + /* Check outgoing MTU */ + if (len > chan->omtu) { + err = -EMSGSIZE; + break; + } - __skb_queue_tail(&chan->tx_q, skb); + __skb_queue_head_init(&seg_queue); - if (chan->tx_send_head == NULL) - chan->tx_send_head = skb; + /* Do segmentation before calling in to the state machine, + * since it's possible to block while waiting for memory + * allocation. + */ + err = l2cap_segment_sdu(chan, &seg_queue, msg, len); - } else { - /* Segment SDU into multiples PDUs */ - err = l2cap_sar_segment_sdu(chan, msg, len); - if (err < 0) - return err; + /* The channel could have been closed while segmenting, + * check that it is still connected. + */ + if (chan->state != BT_CONNECTED) { + __skb_queue_purge(&seg_queue); + err = -ENOTCONN; } - if (chan->mode == L2CAP_MODE_STREAMING) { - l2cap_streaming_send(chan); - err = len; + if (err) break; - } - if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) && - test_bit(CONN_WAIT_F, &chan->conn_state)) { - err = len; - break; - } + if (chan->mode == L2CAP_MODE_ERTM && chan->tx_send_head == NULL) + chan->tx_send_head = seg_queue.next; + skb_queue_splice_tail_init(&seg_queue, &chan->tx_q); + + if (chan->mode == L2CAP_MODE_ERTM) + err = l2cap_ertm_send(chan); + else + l2cap_streaming_send(chan); - err = l2cap_ertm_send(chan); if (err >= 0) err = len; + /* If the skbs were not queued for sending, they'll still be in + * seg_queue and need to be purged. + */ + __skb_queue_purge(&seg_queue); break; default: @@ -1801,9 +2151,9 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); - rcu_read_lock(); + mutex_lock(&conn->chan_lock); - list_for_each_entry_rcu(chan, &conn->chan_l, list) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; if (chan->chan_type != L2CAP_CHAN_RAW) continue; @@ -1819,7 +2169,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) kfree_skb(nskb); } - rcu_read_unlock(); + mutex_unlock(&conn->chan_lock); } /* ---- L2CAP signalling commands ---- */ @@ -1987,18 +2337,38 @@ static void l2cap_ack_timeout(struct work_struct *work) BT_DBG("chan %p", chan); - lock_sock(chan->sk); - l2cap_send_ack(chan); - release_sock(chan->sk); + l2cap_chan_lock(chan); + + __l2cap_send_ack(chan); + + l2cap_chan_unlock(chan); + + l2cap_chan_put(chan); } -static inline void l2cap_ertm_init(struct l2cap_chan *chan) +static inline int l2cap_ertm_init(struct l2cap_chan *chan) { + int err; + + chan->next_tx_seq = 0; + chan->expected_tx_seq = 0; chan->expected_ack_seq = 0; chan->unacked_frames = 0; chan->buffer_seq = 0; chan->num_acked = 0; chan->frames_sent = 0; + chan->last_acked_seq = 0; + chan->sdu = NULL; + chan->sdu_last_frag = NULL; + chan->sdu_len = 0; + + skb_queue_head_init(&chan->tx_q); + + if (chan->mode != L2CAP_MODE_ERTM) + return 0; + + chan->rx_state = L2CAP_RX_STATE_RECV; + chan->tx_state = L2CAP_TX_STATE_XMIT; INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout); INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout); @@ -2007,6 +2377,11 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) skb_queue_head_init(&chan->srej_q); INIT_LIST_HEAD(&chan->srej_l); + err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win); + if (err < 0) + return err; + + return l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win); } static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) @@ -2330,9 +2705,9 @@ done: chan->remote_mps = size; rfc.retrans_timeout = - le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO); + __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); rfc.monitor_timeout = - le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO); + __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); set_bit(CONF_MODE_DONE, &chan->conf_state); @@ -2596,10 +2971,10 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd u16 dcid = 0, scid = __le16_to_cpu(req->scid); __le16 psm = req->psm; - BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); + BT_DBG("psm 0x%2.2x scid 0x%4.4x", __le16_to_cpu(psm), scid); /* Check if we have socket listening on psm */ - pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src); + pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src, conn->dst); if (!pchan) { result = L2CAP_CR_BAD_PSM; goto sendresp; @@ -2607,6 +2982,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd parent = pchan->sk; + mutex_lock(&conn->chan_lock); lock_sock(parent); /* Check if the ACL is secure enough (if not SDP) */ @@ -2647,7 +3023,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd bt_accept_enqueue(parent, sk); - l2cap_chan_add(conn, chan); + __l2cap_chan_add(conn, chan); dcid = chan->scid; @@ -2657,29 +3033,30 @@ 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_chan_check_security(chan)) { - if (bt_sk(sk)->defer_setup) { - l2cap_state_change(chan, BT_CONNECT2); + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { + __l2cap_state_change(chan, BT_CONNECT2); result = L2CAP_CR_PEND; status = L2CAP_CS_AUTHOR_PEND; parent->sk_data_ready(parent, 0); } else { - l2cap_state_change(chan, BT_CONFIG); + __l2cap_state_change(chan, BT_CONFIG); result = L2CAP_CR_SUCCESS; status = L2CAP_CS_NO_INFO; } } else { - l2cap_state_change(chan, BT_CONNECT2); + __l2cap_state_change(chan, BT_CONNECT2); result = L2CAP_CR_PEND; status = L2CAP_CS_AUTHEN_PEND; } } else { - l2cap_state_change(chan, BT_CONNECT2); + __l2cap_state_change(chan, BT_CONNECT2); result = L2CAP_CR_PEND; status = L2CAP_CS_NO_INFO; } response: release_sock(parent); + mutex_unlock(&conn->chan_lock); sendresp: rsp.scid = cpu_to_le16(scid); @@ -2695,8 +3072,7 @@ sendresp: 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); @@ -2719,27 +3095,36 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data; u16 scid, dcid, result, status; struct l2cap_chan *chan; - struct sock *sk; u8 req[128]; + int err; scid = __le16_to_cpu(rsp->scid); dcid = __le16_to_cpu(rsp->dcid); result = __le16_to_cpu(rsp->result); status = __le16_to_cpu(rsp->status); - BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); + BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", + dcid, scid, result, status); + + mutex_lock(&conn->chan_lock); if (scid) { - chan = l2cap_get_chan_by_scid(conn, scid); - if (!chan) - return -EFAULT; + chan = __l2cap_get_chan_by_scid(conn, scid); + if (!chan) { + err = -EFAULT; + goto unlock; + } } else { - chan = l2cap_get_chan_by_ident(conn, cmd->ident); - if (!chan) - return -EFAULT; + chan = __l2cap_get_chan_by_ident(conn, cmd->ident); + if (!chan) { + err = -EFAULT; + goto unlock; + } } - sk = chan->sk; + err = 0; + + l2cap_chan_lock(chan); switch (result) { case L2CAP_CR_SUCCESS: @@ -2765,8 +3150,12 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd break; } - release_sock(sk); - return 0; + l2cap_chan_unlock(chan); + +unlock: + mutex_unlock(&conn->chan_lock); + + return err; } static inline void set_default_fcs(struct l2cap_chan *chan) @@ -2786,8 +3175,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr u16 dcid, flags; u8 rsp[64]; struct l2cap_chan *chan; - struct sock *sk; - int len; + int len, err = 0; dcid = __le16_to_cpu(req->dcid); flags = __le16_to_cpu(req->flags); @@ -2798,8 +3186,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (!chan) return -ENOENT; - sk = chan->sk; - if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) { struct l2cap_cmd_rej_cid rej; @@ -2854,13 +3240,15 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_state_change(chan, BT_CONNECTED); - chan->next_tx_seq = 0; - chan->expected_tx_seq = 0; - skb_queue_head_init(&chan->tx_q); - if (chan->mode == L2CAP_MODE_ERTM) - l2cap_ertm_init(chan); + if (chan->mode == L2CAP_MODE_ERTM || + chan->mode == L2CAP_MODE_STREAMING) + err = l2cap_ertm_init(chan); + + if (err < 0) + l2cap_send_disconn_req(chan->conn, chan, -err); + else + l2cap_chan_ready(chan); - l2cap_chan_ready(sk); goto unlock; } @@ -2887,8 +3275,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr } unlock: - release_sock(sk); - return 0; + l2cap_chan_unlock(chan); + return err; } static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) @@ -2896,22 +3284,20 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data; u16 scid, flags, result; struct l2cap_chan *chan; - struct sock *sk; - int len = cmd->len - sizeof(*rsp); + int len = le16_to_cpu(cmd->len) - sizeof(*rsp); + int err = 0; scid = __le16_to_cpu(rsp->scid); flags = __le16_to_cpu(rsp->flags); result = __le16_to_cpu(rsp->result); - BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", - scid, flags, result); + BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x len %d", scid, flags, + result, len); chan = l2cap_get_chan_by_scid(conn, scid); if (!chan) return 0; - sk = chan->sk; - switch (result) { case L2CAP_CONF_SUCCESS: l2cap_conf_rfc_get(chan, rsp->data, len); @@ -2969,9 +3355,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr } default: - sk->sk_err = ECONNRESET; - __set_chan_timer(chan, - msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT)); + l2cap_chan_set_err(chan, ECONNRESET); + + __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT); l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; } @@ -2985,18 +3371,19 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr set_default_fcs(chan); l2cap_state_change(chan, BT_CONNECTED); - chan->next_tx_seq = 0; - chan->expected_tx_seq = 0; - skb_queue_head_init(&chan->tx_q); - if (chan->mode == L2CAP_MODE_ERTM) - l2cap_ertm_init(chan); + if (chan->mode == L2CAP_MODE_ERTM || + chan->mode == L2CAP_MODE_STREAMING) + err = l2cap_ertm_init(chan); - l2cap_chan_ready(sk); + if (err < 0) + l2cap_send_disconn_req(chan->conn, chan, -err); + else + l2cap_chan_ready(chan); } done: - release_sock(sk); - return 0; + l2cap_chan_unlock(chan); + return err; } static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) @@ -3012,9 +3399,15 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); - chan = l2cap_get_chan_by_scid(conn, dcid); - if (!chan) + mutex_lock(&conn->chan_lock); + + chan = __l2cap_get_chan_by_scid(conn, dcid); + if (!chan) { + mutex_unlock(&conn->chan_lock); return 0; + } + + l2cap_chan_lock(chan); sk = chan->sk; @@ -3022,12 +3415,20 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd rsp.scid = cpu_to_le16(chan->dcid); l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp); + lock_sock(sk); sk->sk_shutdown = SHUTDOWN_MASK; + release_sock(sk); + l2cap_chan_hold(chan); l2cap_chan_del(chan, ECONNRESET); - release_sock(sk); + + l2cap_chan_unlock(chan); chan->ops->close(chan->data); + l2cap_chan_put(chan); + + mutex_unlock(&conn->chan_lock); + return 0; } @@ -3036,23 +3437,32 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data; u16 dcid, scid; struct l2cap_chan *chan; - struct sock *sk; scid = __le16_to_cpu(rsp->scid); dcid = __le16_to_cpu(rsp->dcid); BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); - chan = l2cap_get_chan_by_scid(conn, scid); - if (!chan) + mutex_lock(&conn->chan_lock); + + chan = __l2cap_get_chan_by_scid(conn, scid); + if (!chan) { + mutex_unlock(&conn->chan_lock); return 0; + } - sk = chan->sk; + l2cap_chan_lock(chan); + l2cap_chan_hold(chan); l2cap_chan_del(chan, 0); - release_sock(sk); + + l2cap_chan_unlock(chan); chan->ops->close(chan->data); + l2cap_chan_put(chan); + + mutex_unlock(&conn->chan_lock); + return 0; } @@ -3132,7 +3542,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm 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) { @@ -3149,11 +3560,15 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm 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; @@ -3181,8 +3596,8 @@ static inline int l2cap_create_channel_req(struct l2cap_conn *conn, /* Placeholder: Always reject */ rsp.dcid = 0; rsp.scid = cpu_to_le16(scid); - rsp.result = L2CAP_CR_NO_MEM; - rsp.status = L2CAP_CS_NO_INFO; + rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM); + rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP, sizeof(rsp), &rsp); @@ -3581,19 +3996,19 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, struct sk_buff *next_skb; int tx_seq_offset, next_tx_seq_offset; - bt_cb(skb)->tx_seq = tx_seq; - bt_cb(skb)->sar = sar; + bt_cb(skb)->control.txseq = tx_seq; + bt_cb(skb)->control.sar = sar; next_skb = skb_peek(&chan->srej_q); tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq); while (next_skb) { - if (bt_cb(next_skb)->tx_seq == tx_seq) + if (bt_cb(next_skb)->control.txseq == tx_seq) return -EINVAL; next_tx_seq_offset = __seq_offset(chan, - bt_cb(next_skb)->tx_seq, chan->buffer_seq); + bt_cb(next_skb)->control.txseq, chan->buffer_seq); if (next_tx_seq_offset > tx_seq_offset) { __skb_queue_before(&chan->srej_q, next_skb, skb); @@ -3713,19 +4128,12 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u3 static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan) { - u32 control; - BT_DBG("chan %p, Enter local busy", chan); set_bit(CONN_LOCAL_BUSY, &chan->conn_state); + l2cap_seq_list_clear(&chan->srej_list); - control = __set_reqseq(chan, chan->buffer_seq); - control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR); - l2cap_send_sframe(chan, control); - - set_bit(CONN_RNR_SENT, &chan->conn_state); - - __clear_ack_timer(chan); + __set_ack_timer(chan); } static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan) @@ -3772,11 +4180,11 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq) !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { int err; - if (bt_cb(skb)->tx_seq != tx_seq) + if (bt_cb(skb)->control.txseq != tx_seq) break; skb = skb_dequeue(&chan->srej_q); - control = __set_ctrl_sar(chan, bt_cb(skb)->sar); + control = __set_ctrl_sar(chan, bt_cb(skb)->control.sar); err = l2cap_reassemble_sdu(chan, skb, control); if (err < 0) { @@ -3816,6 +4224,7 @@ static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq) while (tx_seq != chan->expected_tx_seq) { control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ); control |= __set_reqseq(chan, chan->expected_tx_seq); + l2cap_seq_list_append(&chan->srej_list, chan->expected_tx_seq); l2cap_send_sframe(chan, control); new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); @@ -3865,8 +4274,11 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont goto drop; } - if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) + if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { + if (!test_bit(CONN_RNR_SENT, &chan->conn_state)) + l2cap_send_ack(chan); goto drop; + } if (tx_seq == chan->expected_tx_seq) goto expected; @@ -3927,15 +4339,15 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont __skb_queue_head_init(&chan->srej_q); l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); - set_bit(CONN_SEND_PBIT, &chan->conn_state); + /* Set P-bit only if there are some I-frames to ack. */ + if (__clear_ack_timer(chan)) + set_bit(CONN_SEND_PBIT, &chan->conn_state); err = l2cap_send_srejframe(chan, tx_seq); if (err < 0) { l2cap_send_disconn_req(chan->conn, chan, -err); return err; } - - __clear_ack_timer(chan); } return 0; @@ -3943,8 +4355,8 @@ expected: chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq); if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) { - bt_cb(skb)->tx_seq = tx_seq; - bt_cb(skb)->sar = sar; + bt_cb(skb)->control.txseq = tx_seq; + bt_cb(skb)->control.sar = sar; __skb_queue_tail(&chan->srej_q, skb); return 0; } @@ -4135,13 +4547,14 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_cont return 0; } -static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) +static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; u32 control; u16 req_seq; int len, next_tx_seq_offset, req_seq_offset; + __unpack_control(chan, skb); + control = __get_control(chan, skb->data); skb_pull(skb, __ctrl_size(chan)); len = skb->len; @@ -4205,7 +4618,6 @@ drop: static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) { struct l2cap_chan *chan; - struct sock *sk = NULL; u32 control; u16 tx_seq; int len; @@ -4213,11 +4625,11 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk chan = l2cap_get_chan_by_scid(conn, cid); if (!chan) { BT_DBG("unknown cid 0x%4.4x", cid); - goto drop; + /* Drop packet and return */ + kfree_skb(skb); + return 0; } - sk = chan->sk; - BT_DBG("chan %p, len %d", chan, skb->len); if (chan->state != BT_CONNECTED) @@ -4238,7 +4650,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk break; case L2CAP_MODE_ERTM: - l2cap_ertm_data_rcv(sk, skb); + l2cap_ertm_data_rcv(chan, skb); goto done; @@ -4287,26 +4699,20 @@ drop: kfree_skb(skb); done: - if (sk) - release_sock(sk); + l2cap_chan_unlock(chan); 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); + chan = l2cap_global_chan_by_psm(0, psm, conn->src, conn->dst); 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; @@ -4315,31 +4721,24 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str 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) +static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid, + struct sk_buff *skb) { - struct sock *sk = NULL; struct l2cap_chan *chan; - chan = l2cap_global_chan_by_scid(0, cid, conn->src); + chan = l2cap_global_chan_by_scid(0, cid, conn->src, conn->dst); 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; @@ -4348,14 +4747,11 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct 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; } @@ -4383,7 +4779,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) break; case L2CAP_CID_CONN_LESS: - psm = get_unaligned_le16(skb->data); + psm = get_unaligned((__le16 *) skb->data); skb_pull(skb, 2); l2cap_conless_channel(conn, psm, skb); break; @@ -4478,9 +4874,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) 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 { @@ -4500,81 +4894,80 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) BT_DBG("conn %p", conn); if (hcon->type == LE_LINK) { - smp_distribute_keys(conn, 0); + if (!status && encrypt) + smp_distribute_keys(conn, 0); cancel_delayed_work(&conn->security_timer); } - rcu_read_lock(); - - list_for_each_entry_rcu(chan, &conn->chan_l, list) { - struct sock *sk = chan->sk; + mutex_lock(&conn->chan_lock); - bh_lock_sock(sk); + list_for_each_entry(chan, &conn->chan_l, list) { + l2cap_chan_lock(chan); BT_DBG("chan->scid %d", chan->scid); if (chan->scid == L2CAP_CID_LE_DATA) { if (!status && encrypt) { chan->sec_level = hcon->sec_level; - l2cap_chan_ready(sk); + l2cap_chan_ready(chan); } - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) { - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } if (!status && (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)) { + struct sock *sk = chan->sk; + + clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); + sk->sk_state_change(sk); + l2cap_check_encryption(chan, encrypt); - bh_unlock_sock(sk); + 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; struct l2cap_conn_rsp rsp; __u16 res, stat; + lock_sock(sk); + if (!status) { - if (bt_sk(sk)->defer_setup) { + if (test_bit(BT_SK_DEFER_SETUP, + &bt_sk(sk)->flags)) { struct sock *parent = bt_sk(sk)->parent; res = L2CAP_CR_PEND; stat = L2CAP_CS_AUTHOR_PEND; if (parent) parent->sk_data_ready(parent, 0); } else { - l2cap_state_change(chan, BT_CONFIG); + __l2cap_state_change(chan, BT_CONFIG); res = L2CAP_CR_SUCCESS; stat = L2CAP_CS_NO_INFO; } } else { - l2cap_state_change(chan, BT_DISCONN); - __set_chan_timer(chan, - msecs_to_jiffies(L2CAP_DISC_TIMEOUT)); + __l2cap_state_change(chan, BT_DISCONN); + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); res = L2CAP_CR_SEC_BLOCK; stat = L2CAP_CS_NO_INFO; } + release_sock(sk); + rsp.scid = cpu_to_le16(chan->dcid); rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(res); @@ -4583,10 +4976,10 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) sizeof(rsp), &rsp); } - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); } - rcu_read_unlock(); + mutex_unlock(&conn->chan_lock); return 0; } @@ -4605,8 +4998,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) if (!(flags & ACL_CONT)) { struct l2cap_hdr *hdr; - struct l2cap_chan *chan; - u16 cid; int len; if (conn->rx_len) { @@ -4626,7 +5017,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) hdr = (struct l2cap_hdr *) skb->data; len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE; - cid = __le16_to_cpu(hdr->cid); if (len == skb->len) { /* Complete frame received */ @@ -4643,22 +5033,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) goto drop; } - chan = l2cap_get_chan_by_scid(conn, cid); - - if (chan && chan->sk) { - struct sock *sk = chan->sk; - - if (chan->imtu < len - L2CAP_HDR_SIZE) { - BT_ERR("Frame exceeding recv MTU (len %d, " - "MTU %d)", len, - chan->imtu); - release_sock(sk); - l2cap_conn_unreliable(conn, ECOMM); - goto drop; - } - release_sock(sk); - } - /* Allocate skb for the complete frame (with header) */ conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC); if (!conn->rx_skb) @@ -4717,7 +5091,7 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p) c->state, __le16_to_cpu(c->psm), c->scid, c->dcid, c->imtu, c->omtu, c->sec_level, c->mode); -} + } read_unlock(&chan_list_lock); |