diff options
author | Mark Brown <broonie@sirena.org.uk> | 2013-06-14 17:42:49 +0100 |
---|---|---|
committer | Mark Brown <broonie@sirena.org.uk> | 2013-06-14 17:42:49 +0100 |
commit | c4d0a06860b8ade51836f07ae050245f9059c6d6 (patch) | |
tree | 88931d8ccb3cc94bb2a895149ff18dfc448e3324 /net/bluetooth | |
parent | ebb7c3b1a10a2cd3986f2db60612d2c6fbb915ab (diff) | |
parent | 1f76bce8544acd38f7bb1e822540f8ca521e1b7f (diff) |
Merge remote-tracking branch 'jstultz-android/linaro-fixes/experimental/android-3.9' into merge-androidlsk-android-2013.06
Conflicts:
arch/arm/common/Makefile
arch/arm/include/asm/irq.h
arch/arm/include/asm/smp.h
arch/arm/kernel/smp.c
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/af_bluetooth.c | 34 | ||||
-rw-r--r-- | net/bluetooth/amp.c | 2 | ||||
-rw-r--r-- | net/bluetooth/hci_conn.c | 57 | ||||
-rwxr-xr-x[-rw-r--r--] | net/bluetooth/hci_event.c | 20 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 4 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 4 | ||||
-rw-r--r-- | net/bluetooth/rfcomm/core.c | 1 | ||||
-rw-r--r-- | net/bluetooth/sco.c | 54 |
8 files changed, 133 insertions, 43 deletions
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 0d1b08cc76e..2f3aedd11b2 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -30,6 +30,11 @@ #include <net/bluetooth/bluetooth.h> #include <linux/proc_fs.h> +#ifndef CONFIG_BT_SOCK_DEBUG +#undef BT_DBG +#define BT_DBG(D...) +#endif + #define VERSION "2.16" /* Bluetooth sockets */ @@ -112,11 +117,40 @@ int bt_sock_unregister(int proto) } EXPORT_SYMBOL(bt_sock_unregister); +#ifdef CONFIG_PARANOID_NETWORK +static inline int current_has_bt_admin(void) +{ + return !current_euid(); +} + +static inline int current_has_bt(void) +{ + return current_has_bt_admin(); +} +# else +static inline int current_has_bt_admin(void) +{ + return 1; +} + +static inline int current_has_bt(void) +{ + return 1; +} +#endif + static int bt_sock_create(struct net *net, struct socket *sock, int proto, int kern) { int err; + if (proto == BTPROTO_RFCOMM || proto == BTPROTO_SCO || + proto == BTPROTO_L2CAP) { + if (!current_has_bt()) + return -EPERM; + } else if (!current_has_bt_admin()) + return -EPERM; + if (net != &init_net) return -EAFNOSUPPORT; diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index d459ed43c77..a3f3380c209 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -113,7 +113,7 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, bdaddr_t *dst = mgr->l2cap_conn->dst; struct hci_conn *hcon; - hcon = hci_conn_add(hdev, AMP_LINK, dst); + hcon = hci_conn_add(hdev, AMP_LINK, 0, dst); if (!hcon) return NULL; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 4925a02ae7e..2c3aaf83e4b 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -342,7 +342,8 @@ static void hci_conn_auto_accept(unsigned long arg) &conn->dst); } -struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, + __u16 pkt_type, bdaddr_t *dst) { struct hci_conn *conn; @@ -370,14 +371,22 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; break; case SCO_LINK: - if (lmp_esco_capable(hdev)) - conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) | - (hdev->esco_type & EDR_ESCO_MASK); - else - conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK; - break; + if (!pkt_type) + pkt_type = SCO_ESCO_MASK; case ESCO_LINK: - conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK; + if (!pkt_type) + pkt_type = ALL_ESCO_MASK; + if (lmp_esco_capable(hdev)) { + /* HCI Setup Synchronous Connection Command uses + reverse logic on the EDR_ESCO_MASK bits */ + conn->pkt_type = (pkt_type ^ EDR_ESCO_MASK) & + hdev->esco_type; + } else { + /* Legacy HCI Add Sco Connection Command uses a + shifted bitmask */ + conn->pkt_type = (pkt_type << 5) & hdev->pkt_type & + SCO_PTYPE_MASK; + } break; } @@ -511,7 +520,7 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, if (le) return ERR_PTR(-EBUSY); - le = hci_conn_add(hdev, LE_LINK, dst); + le = hci_conn_add(hdev, LE_LINK, 0, dst); if (!le) return ERR_PTR(-ENOMEM); @@ -534,7 +543,7 @@ static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); if (!acl) { - acl = hci_conn_add(hdev, ACL_LINK, dst); + acl = hci_conn_add(hdev, ACL_LINK, 0, dst); if (!acl) return ERR_PTR(-ENOMEM); } @@ -552,7 +561,8 @@ static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, } static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, - bdaddr_t *dst, u8 sec_level, u8 auth_type) + __u16 pkt_type, bdaddr_t *dst, + u8 sec_level, u8 auth_type) { struct hci_conn *acl; struct hci_conn *sco; @@ -563,7 +573,7 @@ static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, sco = hci_conn_hash_lookup_ba(hdev, type, dst); if (!sco) { - sco = hci_conn_add(hdev, type, dst); + sco = hci_conn_add(hdev, type, pkt_type, dst); if (!sco) { hci_conn_put(acl); return ERR_PTR(-ENOMEM); @@ -593,7 +603,8 @@ static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, } /* Create SCO, ACL or LE connection. */ -struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, +struct hci_conn *hci_connect(struct hci_dev *hdev, int type, + __u16 pkt_type, bdaddr_t *dst, __u8 dst_type, __u8 sec_level, __u8 auth_type) { BT_DBG("%s dst %pMR type 0x%x", hdev->name, dst, type); @@ -605,7 +616,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, return hci_connect_acl(hdev, dst, sec_level, auth_type); case SCO_LINK: case ESCO_LINK: - return hci_connect_sco(hdev, type, dst, sec_level, auth_type); + return hci_connect_sco(hdev, type, pkt_type, dst, sec_level, auth_type); } return ERR_PTR(-EINVAL); @@ -884,6 +895,15 @@ int hci_get_conn_list(void __user *arg) (ci + n)->out = c->out; (ci + n)->state = c->state; (ci + n)->link_mode = c->link_mode; + if (c->type == SCO_LINK) { + (ci + n)->mtu = hdev->sco_mtu; + (ci + n)->cnt = hdev->sco_cnt; + (ci + n)->pkts = hdev->sco_pkts; + } else { + (ci + n)->mtu = hdev->acl_mtu; + (ci + n)->cnt = hdev->acl_cnt; + (ci + n)->pkts = hdev->acl_pkts; + } if (++n >= req.conn_num) break; } @@ -920,6 +940,15 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg) ci.out = conn->out; ci.state = conn->state; ci.link_mode = conn->link_mode; + if (req.type == SCO_LINK) { + ci.mtu = hdev->sco_mtu; + ci.cnt = hdev->sco_cnt; + ci.pkts = hdev->sco_pkts; + } else { + ci.mtu = hdev->acl_mtu; + ci.cnt = hdev->acl_cnt; + ci.pkts = hdev->acl_pkts; + } } hci_dev_unlock(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 477726a6351..6ce42b45426 100644..100755 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1456,7 +1456,7 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) } } else { if (!conn) { - conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr); + conn = hci_conn_add(hdev, ACL_LINK, 0, &cp->bdaddr); if (conn) { conn->out = true; conn->link_mode |= HCI_LM_MASTER; @@ -2131,6 +2131,15 @@ void hci_conn_accept(struct hci_conn *conn, int mask) } } +static inline bool is_sco_active(struct hci_dev *hdev) +{ + if (hci_conn_hash_lookup_state(hdev, SCO_LINK, BT_CONNECTED) || + (hci_conn_hash_lookup_state(hdev, ESCO_LINK, + BT_CONNECTED))) + return true; + return false; +} + static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_request *ev = (void *) skb->data; @@ -2158,7 +2167,8 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); if (!conn) { - conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr); + /* pkt_type not yet used for incoming connections */ + conn = hci_conn_add(hdev, ev->link_type, 0, &ev->bdaddr); if (!conn) { BT_ERR("No memory for new connection"); hci_dev_unlock(hdev); @@ -2177,7 +2187,8 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) bacpy(&cp.bdaddr, &ev->bdaddr); - if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) + if (lmp_rswitch_capable(hdev) && ((mask & HCI_LM_MASTER) + || is_sco_active(hdev))) cp.role = 0x00; /* Become master */ else cp.role = 0x01; /* Remain slave */ @@ -3366,6 +3377,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, hci_conn_add_sysfs(conn); break; + case 0x10: /* Connection Accept Timeout */ case 0x11: /* Unsupported Feature or Parameter Value */ case 0x1c: /* SCO interval rejected */ case 0x1a: /* Unsupported Remote Feature */ @@ -3942,7 +3954,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); if (!conn) { - conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr); + conn = hci_conn_add(hdev, LE_LINK, 0, &ev->bdaddr); if (!conn) { BT_ERR("No memory for new connection"); goto unlock; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7c7e9321f1e..adf65faa176 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1684,10 +1684,10 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, auth_type = l2cap_get_auth_type(chan); if (chan->dcid == L2CAP_CID_LE_DATA) - hcon = hci_connect(hdev, LE_LINK, dst, dst_type, + hcon = hci_connect(hdev, LE_LINK, 0, dst, dst_type, chan->sec_level, auth_type); else - hcon = hci_connect(hdev, ACL_LINK, dst, dst_type, + hcon = hci_connect(hdev, ACL_LINK, 0, dst, dst_type, chan->sec_level, auth_type); if (IS_ERR(hcon)) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 39395c7144a..078ec4d86b7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2041,10 +2041,10 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, auth_type = HCI_AT_DEDICATED_BONDING_MITM; if (cp->addr.type == BDADDR_BREDR) - conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, + conn = hci_connect(hdev, ACL_LINK, 0, &cp->addr.bdaddr, cp->addr.type, sec_level, auth_type); else - conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, + conn = hci_connect(hdev, LE_LINK, 0, &cp->addr.bdaddr, cp->addr.type, sec_level, auth_type); if (IS_ERR(conn)) { diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index b23e2713fea..ed1ff77cf1a 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -448,7 +448,6 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) switch (d->state) { case BT_CONNECT: - case BT_CONFIG: if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) { set_bit(RFCOMM_AUTH_REJECT, &d->flags); rfcomm_schedule(); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index fb6192c9812..73e9083cb93 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -158,6 +158,7 @@ static int sco_connect(struct sock *sk) { bdaddr_t *src = &bt_sk(sk)->src; bdaddr_t *dst = &bt_sk(sk)->dst; + __u16 pkt_type = sco_pi(sk)->pkt_type; struct sco_conn *conn; struct hci_conn *hcon; struct hci_dev *hdev; @@ -173,11 +174,13 @@ static int sco_connect(struct sock *sk) if (lmp_esco_capable(hdev) && !disable_esco) type = ESCO_LINK; - else + else { type = SCO_LINK; + pkt_type &= SCO_ESCO_MASK; + } - hcon = hci_connect(hdev, type, dst, BDADDR_BREDR, BT_SECURITY_LOW, - HCI_AT_NO_BONDING); + hcon = hci_connect(hdev, type, pkt_type, dst, BDADDR_BREDR, + BT_SECURITY_LOW, HCI_AT_NO_BONDING); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto done; @@ -445,17 +448,21 @@ static int sco_sock_create(struct net *net, struct socket *sock, int protocol, return 0; } -static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) +static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) { - struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; + struct sockaddr_sco sa; struct sock *sk = sock->sk; - int err = 0; + int len, err = 0; - BT_DBG("sk %p %pMR", sk, &sa->sco_bdaddr); + BT_DBG("sk %p %pMR", sk, &sa.sco_bdaddr); if (!addr || addr->sa_family != AF_BLUETOOTH) return -EINVAL; + memset(&sa, 0, sizeof(sa)); + len = min_t(unsigned int, sizeof(sa), alen); + memcpy(&sa, addr, len); + lock_sock(sk); if (sk->sk_state != BT_OPEN) { @@ -468,7 +475,8 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le goto done; } - bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr); + bacpy(&bt_sk(sk)->src, &sa.sco_bdaddr); + sco_pi(sk)->pkt_type = sa.sco_pkt_type; sk->sk_state = BT_BOUND; @@ -479,27 +487,34 @@ done: static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) { - struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; struct sock *sk = sock->sk; - int err = 0; - + struct sockaddr_sco sa; + int len, err = 0; BT_DBG("sk %p", sk); - if (alen < sizeof(struct sockaddr_sco) || - addr->sa_family != AF_BLUETOOTH) + if (!addr || addr->sa_family != AF_BLUETOOTH) return -EINVAL; - if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) - return -EBADFD; - - if (sk->sk_type != SOCK_SEQPACKET) - return -EINVAL; + memset(&sa, 0, sizeof(sa)); + len = min_t(unsigned int, sizeof(sa), alen); + memcpy(&sa, addr, len); lock_sock(sk); + if (sk->sk_type != SOCK_SEQPACKET) { + err = -EINVAL; + goto done; + } + + if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) { + err = -EBADFD; + goto done; + } + /* Set destination address and psm */ - bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr); + bacpy(&bt_sk(sk)->dst, &sa.sco_bdaddr); + sco_pi(sk)->pkt_type = sa.sco_pkt_type; err = sco_connect(sk); if (err) @@ -623,6 +638,7 @@ static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len bacpy(&sa->sco_bdaddr, &bt_sk(sk)->dst); else bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src); + sa->sco_pkt_type = sco_pi(sk)->pkt_type; return 0; } |