aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/l2cap_core.c')
-rw-r--r--net/bluetooth/l2cap_core.c144
1 files changed, 76 insertions, 68 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 323f23cd2c37..8680aae678ce 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -40,7 +40,6 @@
#include "smp.h"
#include "a2mp.h"
#include "amp.h"
-#include "6lowpan.h"
#define LE_FLOWCTL_MAX_CREDITS 65535
@@ -205,6 +204,7 @@ done:
write_unlock(&chan_list_lock);
return err;
}
+EXPORT_SYMBOL_GPL(l2cap_add_psm);
int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
{
@@ -437,6 +437,7 @@ struct l2cap_chan *l2cap_chan_create(void)
return chan;
}
+EXPORT_SYMBOL_GPL(l2cap_chan_create);
static void l2cap_chan_destroy(struct kref *kref)
{
@@ -464,6 +465,7 @@ void l2cap_chan_put(struct l2cap_chan *c)
kref_put(&c->kref, l2cap_chan_destroy);
}
+EXPORT_SYMBOL_GPL(l2cap_chan_put);
void l2cap_chan_set_defaults(struct l2cap_chan *chan)
{
@@ -482,6 +484,7 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan)
set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
}
+EXPORT_SYMBOL_GPL(l2cap_chan_set_defaults);
static void l2cap_le_flowctl_init(struct l2cap_chan *chan)
{
@@ -614,6 +617,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
return;
}
+EXPORT_SYMBOL_GPL(l2cap_chan_del);
void l2cap_conn_update_id_addr(struct hci_conn *hcon)
{
@@ -717,6 +721,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
break;
}
}
+EXPORT_SYMBOL(l2cap_chan_close);
static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
{
@@ -1455,13 +1460,12 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
static void l2cap_le_conn_ready(struct l2cap_conn *conn)
{
struct hci_conn *hcon = conn->hcon;
+ struct hci_dev *hdev = hcon->hdev;
struct l2cap_chan *chan, *pchan;
u8 dst_type;
BT_DBG("");
- bt_6lowpan_add_conn(conn);
-
/* Check if we have socket listening on cid */
pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT,
&hcon->src, &hcon->dst);
@@ -1475,9 +1479,28 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
dst_type = bdaddr_type(hcon, hcon->dst_type);
/* If device is blocked, do not create a channel for it */
- if (hci_blacklist_lookup(hcon->hdev, &hcon->dst, dst_type))
+ if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type))
return;
+ /* For LE slave connections, make sure the connection interval
+ * is in the range of the minium and maximum interval that has
+ * been configured for this connection. If not, then trigger
+ * the connection update procedure.
+ */
+ if (!test_bit(HCI_CONN_MASTER, &hcon->flags) &&
+ (hcon->le_conn_interval < hcon->le_conn_min_interval ||
+ hcon->le_conn_interval > hcon->le_conn_max_interval)) {
+ struct l2cap_conn_param_update_req req;
+
+ req.min = cpu_to_le16(hcon->le_conn_min_interval);
+ req.max = cpu_to_le16(hcon->le_conn_max_interval);
+ req.latency = cpu_to_le16(hcon->le_conn_latency);
+ req.to_multiplier = cpu_to_le16(hcon->le_supv_timeout);
+
+ l2cap_send_cmd(conn, l2cap_get_ident(conn),
+ L2CAP_CONN_PARAM_UPDATE_REQ, sizeof(req), &req);
+ }
+
l2cap_chan_lock(pchan);
chan = pchan->ops->new_connection(pchan);
@@ -2118,7 +2141,8 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
struct sk_buff **frag;
int sent = 0;
- if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
+ if (chan->ops->memcpy_fromiovec(chan, skb_put(skb, count),
+ msg->msg_iov, count))
return -EFAULT;
sent += count;
@@ -2131,18 +2155,17 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
count = min_t(unsigned int, conn->mtu, len);
- tmp = chan->ops->alloc_skb(chan, count,
+ tmp = chan->ops->alloc_skb(chan, 0, 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))
+ if (chan->ops->memcpy_fromiovec(chan, skb_put(*frag, count),
+ msg->msg_iov, count))
return -EFAULT;
- (*frag)->priority = skb->priority;
-
sent += count;
len -= count;
@@ -2156,26 +2179,23 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
}
static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
- struct msghdr *msg, size_t len,
- u32 priority)
+ struct msghdr *msg, size_t len)
{
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("chan %p psm 0x%2.2x len %zu priority %u", chan,
- __le16_to_cpu(chan->psm), len, priority);
+ BT_DBG("chan %p psm 0x%2.2x len %zu", chan,
+ __le16_to_cpu(chan->psm), len);
count = min_t(unsigned int, (conn->mtu - hlen), len);
- skb = chan->ops->alloc_skb(chan, count + hlen,
+ skb = chan->ops->alloc_skb(chan, hlen, count,
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);
@@ -2191,8 +2211,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
}
static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
- struct msghdr *msg, size_t len,
- u32 priority)
+ struct msghdr *msg, size_t len)
{
struct l2cap_conn *conn = chan->conn;
struct sk_buff *skb;
@@ -2203,13 +2222,11 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len);
- skb = chan->ops->alloc_skb(chan, count + L2CAP_HDR_SIZE,
+ skb = chan->ops->alloc_skb(chan, L2CAP_HDR_SIZE, count,
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);
@@ -2247,7 +2264,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
count = min_t(unsigned int, (conn->mtu - hlen), len);
- skb = chan->ops->alloc_skb(chan, count + hlen,
+ skb = chan->ops->alloc_skb(chan, hlen, count,
msg->msg_flags & MSG_DONTWAIT);
if (IS_ERR(skb))
return skb;
@@ -2368,7 +2385,7 @@ static struct sk_buff *l2cap_create_le_flowctl_pdu(struct l2cap_chan *chan,
count = min_t(unsigned int, (conn->mtu - hlen), len);
- skb = chan->ops->alloc_skb(chan, count + hlen,
+ skb = chan->ops->alloc_skb(chan, hlen, count,
msg->msg_flags & MSG_DONTWAIT);
if (IS_ERR(skb))
return skb;
@@ -2430,8 +2447,7 @@ static int l2cap_segment_le_sdu(struct l2cap_chan *chan,
return 0;
}
-int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
- u32 priority)
+int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
{
struct sk_buff *skb;
int err;
@@ -2442,7 +2458,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
/* Connectionless channel */
if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
- skb = l2cap_create_connless_pdu(chan, msg, len, priority);
+ skb = l2cap_create_connless_pdu(chan, msg, len);
if (IS_ERR(skb))
return PTR_ERR(skb);
@@ -2499,7 +2515,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
return -EMSGSIZE;
/* Create a basic PDU */
- skb = l2cap_create_basic_pdu(chan, msg, len, priority);
+ skb = l2cap_create_basic_pdu(chan, msg, len);
if (IS_ERR(skb))
return PTR_ERR(skb);
@@ -2562,6 +2578,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
return err;
}
+EXPORT_SYMBOL_GPL(l2cap_chan_send);
static void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq)
{
@@ -3217,6 +3234,9 @@ done:
switch (chan->mode) {
case L2CAP_MODE_BASIC:
+ if (disable_ertm)
+ break;
+
if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
!(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
break;
@@ -5197,27 +5217,6 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
return 0;
}
-static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
- u16 to_multiplier)
-{
- u16 max_latency;
-
- if (min > max || min < 6 || max > 3200)
- return -EINVAL;
-
- if (to_multiplier < 10 || to_multiplier > 3200)
- return -EINVAL;
-
- if (max >= to_multiplier * 8)
- return -EINVAL;
-
- max_latency = (to_multiplier * 8 / max) - 1;
- if (latency > 499 || latency > max_latency)
- return -EINVAL;
-
- return 0;
-}
-
static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd,
u16 cmd_len, u8 *data)
@@ -5228,7 +5227,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
u16 min, max, latency, to_multiplier;
int err;
- if (!(hcon->link_mode & HCI_LM_MASTER))
+ if (!test_bit(HCI_CONN_MASTER, &hcon->flags))
return -EINVAL;
if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
@@ -5245,7 +5244,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
memset(&rsp, 0, sizeof(rsp));
- err = l2cap_check_conn_param(min, max, latency, to_multiplier);
+ err = hci_check_conn_params(min, max, latency, to_multiplier);
if (err)
rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
else
@@ -5254,8 +5253,16 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
sizeof(rsp), &rsp);
- if (!err)
- hci_le_conn_update(hcon, min, max, latency, to_multiplier);
+ if (!err) {
+ u8 store_hint;
+
+ store_hint = hci_le_conn_update(hcon, min, max, latency,
+ to_multiplier);
+ mgmt_new_conn_param(hcon->hdev, &hcon->dst, hcon->dst_type,
+ store_hint, min, max, latency,
+ to_multiplier);
+
+ }
return 0;
}
@@ -6879,9 +6886,6 @@ static void l2cap_att_channel(struct l2cap_conn *conn,
BT_DBG("chan %p, len %d", chan, skb->len);
- if (hci_blacklist_lookup(hcon->hdev, &hcon->dst, hcon->dst_type))
- goto drop;
-
if (chan->imtu < skb->len)
goto drop;
@@ -6914,6 +6918,16 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
return;
}
+ /* Since we can't actively block incoming LE connections we must
+ * at least ensure that we ignore incoming data from them.
+ */
+ if (hcon->type == LE_LINK &&
+ hci_bdaddr_list_lookup(&hcon->hdev->blacklist, &hcon->dst,
+ bdaddr_type(hcon, hcon->dst_type))) {
+ kfree_skb(skb);
+ return;
+ }
+
BT_DBG("len %d, cid 0x%4.4x", len, cid);
switch (cid) {
@@ -6940,10 +6954,6 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
l2cap_conn_del(conn->hcon, EACCES);
break;
- case L2CAP_FC_6LOWPAN:
- bt_6lowpan_recv(conn, skb);
- break;
-
default:
l2cap_data_channel(conn, cid, skb);
break;
@@ -7042,7 +7052,6 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
struct l2cap_conn *conn;
struct hci_conn *hcon;
struct hci_dev *hdev;
- __u8 auth_type;
int err;
BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst,
@@ -7118,9 +7127,9 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
chan->psm = psm;
chan->dcid = cid;
- auth_type = l2cap_get_auth_type(chan);
-
if (bdaddr_type_is_le(dst_type)) {
+ bool master;
+
/* Convert from L2CAP channel address type to HCI address type
*/
if (dst_type == BDADDR_LE_PUBLIC)
@@ -7128,9 +7137,12 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
else
dst_type = ADDR_LE_DEV_RANDOM;
+ master = !test_bit(HCI_ADVERTISING, &hdev->dev_flags);
+
hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level,
- auth_type);
+ HCI_LE_CONN_TIMEOUT, master);
} else {
+ u8 auth_type = l2cap_get_auth_type(chan);
hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type);
}
@@ -7190,6 +7202,7 @@ done:
hci_dev_put(hdev);
return err;
}
+EXPORT_SYMBOL_GPL(l2cap_chan_connect);
/* ---- L2CAP interface with lower layer (HCI) ---- */
@@ -7252,8 +7265,6 @@ void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
{
BT_DBG("hcon %p reason %d", hcon, reason);
- bt_6lowpan_del_conn(hcon->l2cap_data);
-
l2cap_conn_del(hcon, bt_to_errno(reason));
}
@@ -7536,14 +7547,11 @@ int __init l2cap_init(void)
debugfs_create_u16("l2cap_le_default_mps", 0644, bt_debugfs,
&le_default_mps);
- bt_6lowpan_init();
-
return 0;
}
void l2cap_exit(void)
{
- bt_6lowpan_cleanup();
debugfs_remove(l2cap_debugfs);
l2cap_cleanup_sockets();
}