/* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org> Copyright (C) 2010 Google Inc. Copyright (C) 2011 ProFUSION Embedded Systems
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED.
*/
if (!bdaddr_type_is_valid(la.l2_bdaddr_type)) return -EINVAL;
if (bdaddr_type_is_le(la.l2_bdaddr_type)) { /* We only allow ATT user space socket */ if (la.l2_cid &&
la.l2_cid != cpu_to_le16(L2CAP_CID_ATT)) return -EINVAL;
}
switch (chan->chan_type) { case L2CAP_CHAN_CONN_LESS: if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_3DSP)
chan->sec_level = BT_SECURITY_SDP; break; case L2CAP_CHAN_CONN_ORIENTED: if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_SDP ||
__le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM)
chan->sec_level = BT_SECURITY_SDP; break; case L2CAP_CHAN_RAW:
chan->sec_level = BT_SECURITY_SDP; break; case L2CAP_CHAN_FIXED: /* Fixed channels default to the L2CAP core not holding a * hci_conn reference for them. For fixed channels mapping to * L2CAP sockets we do want to hold a reference so set the * appropriate flag to request it.
*/
set_bit(FLAG_HOLD_HCI_CONN, &chan->flags); break;
}
/* Use L2CAP_MODE_LE_FLOWCTL (CoC) in case of LE address and * L2CAP_MODE_EXT_FLOWCTL (ECRED) has not been set.
*/ if (chan->psm && bdaddr_type_is_le(chan->src_type) &&
chan->mode != L2CAP_MODE_EXT_FLOWCTL)
chan->mode = L2CAP_MODE_LE_FLOWCTL;
if (!bdaddr_type_is_valid(la.l2_bdaddr_type)) return -EINVAL;
/* Check that the socket wasn't bound to something that * conflicts with the address given to connect(). If chan->src * is BDADDR_ANY it means bind() was never used, in which case * chan->src_type and la.l2_bdaddr_type do not need to match.
*/ if (chan->src_type == BDADDR_BREDR && bacmp(&chan->src, BDADDR_ANY) &&
bdaddr_type_is_le(la.l2_bdaddr_type)) { /* Old user space versions will try to incorrectly bind * the ATT socket using BDADDR_BREDR. We need to accept * this and fix up the source address type only when * both the source CID and destination CID indicate * ATT. Anything else is an invalid combination.
*/ if (chan->scid != L2CAP_CID_ATT ||
la.l2_cid != cpu_to_le16(L2CAP_CID_ATT)) return -EINVAL;
/* We don't have the hdev available here to make a * better decision on random vs public, but since all * user space versions that exhibit this issue anyway do * not support random local addresses assuming public * here is good enough.
*/
chan->src_type = BDADDR_LE_PUBLIC;
}
if (chan->src_type != BDADDR_BREDR && la.l2_bdaddr_type == BDADDR_BREDR) return -EINVAL;
if (bdaddr_type_is_le(la.l2_bdaddr_type)) { /* We only allow ATT user space socket */ if (la.l2_cid &&
la.l2_cid != cpu_to_le16(L2CAP_CID_ATT)) return -EINVAL;
}
/* Use L2CAP_MODE_LE_FLOWCTL (CoC) in case of LE address and * L2CAP_MODE_EXT_FLOWCTL (ECRED) has not been set.
*/ if (chan->psm && bdaddr_type_is_le(chan->src_type) &&
chan->mode != L2CAP_MODE_EXT_FLOWCTL)
chan->mode = L2CAP_MODE_LE_FLOWCTL;
switch (chan->mode) { case L2CAP_MODE_BASIC: case L2CAP_MODE_LE_FLOWCTL: break; case L2CAP_MODE_EXT_FLOWCTL: if (!enable_ecred) {
err = -EOPNOTSUPP; goto done;
} break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: if (!disable_ertm) break;
fallthrough; default:
err = -EOPNOTSUPP; goto done;
}
/* Listening channels need to use nested locking in order not to * cause lockdep warnings when the created child channels end up * being locked in the same thread as the parent channel.
*/
atomic_set(&chan->nesting, L2CAP_NESTING_PARENT);
switch (optname) { case L2CAP_OPTIONS: /* LE sockets should use BT_SNDMTU/BT_RCVMTU, but since * legacy ATT code depends on getsockopt for * L2CAP_OPTIONS we need to let this pass.
*/ if (bdaddr_type_is_le(chan->src_type) &&
chan->scid != L2CAP_CID_ATT) {
err = -EINVAL; break;
}
/* Only BR/EDR modes are supported here */ switch (chan->mode) { case L2CAP_MODE_BASIC: case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: break; default:
err = -EINVAL; break;
}
err = copy_safe_from_sockptr(&opts, sizeof(opts), optval,
optlen); if (err) break;
if (opts.txwin_size > L2CAP_DEFAULT_EXT_WINDOW) {
err = -EINVAL; break;
}
if (!l2cap_valid_mtu(chan, opts.imtu)) {
err = -EINVAL; break;
}
/* Only BR/EDR modes are supported here */ switch (opts.mode) { case L2CAP_MODE_BASIC:
clear_bit(CONF_STATE2_DEVICE, &chan->conf_state); break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: if (!disable_ertm) break;
fallthrough; default:
err = -EINVAL; break;
}
case BT_FLUSHABLE:
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); if (err) break;
if (opt > BT_FLUSHABLE_ON) {
err = -EINVAL; break;
}
if (opt == BT_FLUSHABLE_OFF) {
conn = chan->conn; /* proceed further only when we have l2cap_conn and
No Flush support in the LM */ if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) {
err = -EINVAL; break;
}
}
if (opt)
set_bit(FLAG_FLUSHABLE, &chan->flags); else
clear_bit(FLAG_FLUSHABLE, &chan->flags); break;
case BT_POWER: if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
chan->chan_type != L2CAP_CHAN_RAW) {
err = -EINVAL; break;
}
pwr.force_active = BT_POWER_FORCE_ACTIVE_ON;
err = copy_safe_from_sockptr(&pwr, sizeof(pwr), optval, optlen); if (err) break;
if (pwr.force_active)
set_bit(FLAG_FORCE_ACTIVE, &chan->flags); else
clear_bit(FLAG_FORCE_ACTIVE, &chan->flags); break;
case BT_CHANNEL_POLICY:
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); if (err) break;
err = -EOPNOTSUPP; break;
case BT_SNDMTU: if (!bdaddr_type_is_le(chan->src_type)) {
err = -EINVAL; break;
}
/* Setting is not supported as it's the remote side that * decides this.
*/
err = -EPERM; break;
case BT_RCVMTU: if (!bdaddr_type_is_le(chan->src_type)) {
err = -EINVAL; break;
}
if (avail <= 0) {
l2cap_chan_rx_avail(chan, 0); return;
}
if (!chan->mps) {
l2cap_chan_rx_avail(chan, -1); return;
}
/* Correct available memory by estimated sk_buff overhead. * This is significant due to small transfer sizes. However, accept * at least one full packet if receive space is non-zero.
*/
expected_skbs = DIV_ROUND_UP(avail, chan->mps);
skb_overhead = expected_skbs * sizeof(struct sk_buff); if (skb_overhead < avail)
l2cap_chan_rx_avail(chan, avail - skb_overhead); else
l2cap_chan_rx_avail(chan, -1);
}
/* Attempt to put pending rx data in the socket buffer */ while (!list_empty(&pi->rx_busy)) { struct l2cap_rx_busy *rx_busy =
list_first_entry(&pi->rx_busy, struct l2cap_rx_busy,
list); if (__sock_queue_rcv_skb(sk, rx_busy->skb) < 0) goto done;
list_del(&rx_busy->list);
kfree(rx_busy);
}
/* Restore data flow when half of the receive buffer is * available. This avoids resending large numbers of * frames.
*/ if (test_bit(CONN_LOCAL_BUSY, &pi->chan->conn_state) &&
atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf >> 1)
l2cap_chan_busy(pi->chan, 0);
done:
release_sock(sk); return err;
}
/* Kill socket (only if zapped and orphan) * Must be called on unlocked socket, with l2cap channel lock.
*/ staticvoid l2cap_sock_kill(struct sock *sk)
{ if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket) return;
BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state));
/* Sock is dead, so set chan data to NULL, avoid other task use invalid * sock pointer.
*/
l2cap_pi(sk)->chan->data = NULL; /* Kill poor orphan */
/* After waiting for ACKs, check whether shutdown * has already been actioned to close the L2CAP * link such as by l2cap_disconnection_req().
*/ if ((sk->sk_shutdown & how) == how) goto shutdown_matched;
}
/* Try setting the RCV_SHUTDOWN bit, return early if SEND_SHUTDOWN * is already set
*/ if ((how & RCV_SHUTDOWN) && !(sk->sk_shutdown & RCV_SHUTDOWN)) {
sk->sk_shutdown |= RCV_SHUTDOWN; if ((sk->sk_shutdown & how) == how) goto shutdown_matched;
}
pi = l2cap_pi(sk);
lock_sock(sk); if (chan->mode == L2CAP_MODE_ERTM && !list_empty(&pi->rx_busy)) {
err = -ENOMEM; goto done;
}
if (chan->mode != L2CAP_MODE_ERTM &&
chan->mode != L2CAP_MODE_STREAMING &&
chan->mode != L2CAP_MODE_LE_FLOWCTL &&
chan->mode != L2CAP_MODE_EXT_FLOWCTL) { /* Even if no filter is attached, we could potentially * get errors from security modules, etc.
*/
err = sk_filter(sk, skb); if (err) goto done;
}
err = __sock_queue_rcv_skb(sk, skb);
l2cap_publish_rx_avail(chan);
/* For ERTM and LE, handle a skb that doesn't fit into the recv * buffer. This is important to do because the data frames * have already been acked, so the skb cannot be discarded. * * Notify the l2cap core that the buffer is full, so the * LOCAL_BUSY state is entered and no more frames are * acked and reassembled until there is buffer space * available.
*/ if (err < 0 &&
(chan->mode == L2CAP_MODE_ERTM ||
chan->mode == L2CAP_MODE_LE_FLOWCTL ||
chan->mode == L2CAP_MODE_EXT_FLOWCTL)) { struct l2cap_rx_busy *rx_busy =
kmalloc(sizeof(*rx_busy), GFP_KERNEL); if (!rx_busy) {
err = -ENOMEM; goto done;
}
rx_busy->skb = skb;
list_add_tail(&rx_busy->list, &pi->rx_busy);
l2cap_chan_busy(chan, 1);
err = 0;
}
BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
/* This callback can be called both for server (BT_LISTEN) * sockets as well as "normal" ones. To avoid lockdep warnings * with child socket locking (through l2cap_sock_cleanup_listen) * we need separation into separate nesting levels. The simplest * way to accomplish this is to inherit the nesting level used * for the channel.
*/
lock_sock_nested(sk, atomic_read(&chan->nesting));
parent = bt_sk(sk)->parent;
switch (chan->state) { case BT_OPEN: case BT_BOUND: case BT_CLOSED: break; case BT_LISTEN:
l2cap_sock_cleanup_listen(sk);
sk->sk_state = BT_CLOSED;
chan->state = BT_CLOSED;
/* Channel lock is released before requesting new skb and then * reacquired thus we need to recheck channel state.
*/ if (chan->state != BT_CONNECTED) {
kfree_skb(skb); return ERR_PTR(-ENOTCONN);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.