summaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2013-10-18 11:49:25 +0300
committerMarcel Holtmann <marcel@holtmann.org>2013-10-18 01:53:57 -0700
commiteb622495e89879bb7d62bb27b2561a306bbe2401 (patch)
tree7b3c5955524ca3c83f84ff5d8ded8c2ef02ac23a /net/bluetooth
parent2bfa3531f654d82db01d3121ae2de7a8696a4555 (diff)
downloadlinux-eb622495e89879bb7d62bb27b2561a306bbe2401.tar.bz2
Bluetooth: Fix ATT socket backwards compatibility with user space
Old user space versions bind the Attribute Protocol socket to BDADDR_BREDR when they should be using BDADDR_LE_PUBLIC or BDADDR_LE_RANDOM. The kernel recently introduced stricter checks on the socket parameters but we need to punch this hole for old user space versions to keep them working. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/l2cap_sock.c27
1 files changed, 25 insertions, 2 deletions
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 34e5a58ffca8..1f326d9d9132 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -159,8 +159,31 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
return -EINVAL;
- if (chan->src_type == BDADDR_BREDR && la.l2_bdaddr_type != BDADDR_BREDR)
- 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 != __constant_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;