From bbaf444a89dd7dd7effd8ed2f4e4ec64da3cc1da Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 8 Nov 2012 01:22:59 +0100 Subject: [PATCH 01/15] Bluetooth: Use proper invalid value for tx_power The core specification defines 127 as the "not available" value (well, "reserved" for BR/EDR and "not available" for LE - but essentially the same). Therefore, instead of testing for 0 (which is in fact a valid value) we should be using this invalid value to test if the tx_power is available. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci.h | 3 +++ net/bluetooth/hci_core.c | 2 ++ net/bluetooth/hci_event.c | 2 ++ net/bluetooth/mgmt.c | 2 +- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 6c414f4302f..344fea0a724 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -319,6 +319,9 @@ enum { #define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00 #define HCI_FLOW_CTL_MODE_BLOCK_BASED 0x01 +/* The core spec defines 127 as the "not available" value */ +#define HCI_TX_POWER_INVALID 127 + /* Extended Inquiry Response field types */ #define EIR_FLAGS 0x01 /* flags */ #define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 515d0c394f3..9713a2917dd 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1606,6 +1606,8 @@ struct hci_dev *hci_alloc_dev(void) hdev->esco_type = (ESCO_HV1); hdev->link_mode = (HCI_LM_ACCEPT); hdev->io_capability = 0x03; /* No Input No Output */ + hdev->inq_tx_power = HCI_TX_POWER_INVALID; + hdev->adv_tx_power = HCI_TX_POWER_INVALID; hdev->sniff_max_interval = 800; hdev->sniff_min_interval = 80; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c08ac7c0371..09c65712e8c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -202,6 +202,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) BIT(HCI_PERIODIC_INQ)); hdev->discovery.state = DISCOVERY_STOPPED; + hdev->inq_tx_power = HCI_TX_POWER_INVALID; + hdev->adv_tx_power = HCI_TX_POWER_INVALID; } static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a1a62baaaaf..dedbb1d8b2d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -484,7 +484,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data) ptr += (name_len + 2); } - if (hdev->inq_tx_power) { + if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) { ptr[0] = 2; ptr[1] = EIR_TX_POWER; ptr[2] = (u8) hdev->inq_tx_power; From 3f0f524bafcd2025c12e215f13207c7be0a13bf9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 8 Nov 2012 01:23:00 +0100 Subject: [PATCH 02/15] Bluetooth: Add support for setting LE advertising data This patch adds support for setting basing LE advertising data. The three elements supported for now are the advertising flags, the TX power and the friendly name. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci.h | 15 +++++ include/net/bluetooth/hci_core.h | 4 ++ net/bluetooth/hci_core.c | 94 ++++++++++++++++++++++++++++++++ net/bluetooth/hci_event.c | 11 +++- 4 files changed, 123 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 344fea0a724..7306078e547 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -338,6 +338,13 @@ enum { #define EIR_SSP_RAND_R 0x0F /* Simple Pairing Randomizer R */ #define EIR_DEVICE_ID 0x10 /* device ID */ +/* Low Energy Advertising Flags */ +#define LE_AD_LIMITED 0x01 /* Limited Discoverable */ +#define LE_AD_GENERAL 0x02 /* General Discoverable */ +#define LE_AD_NO_BREDR 0x04 /* BR/EDR not supported */ +#define LE_AD_SIM_LE_BREDR_CTRL 0x08 /* Simultaneous LE & BR/EDR Controller */ +#define LE_AD_SIM_LE_BREDR_HOST 0x10 /* Simultaneous LE & BR/EDR Host */ + /* ----- HCI Commands ---- */ #define HCI_OP_NOP 0x0000 @@ -942,6 +949,14 @@ struct hci_rp_le_read_adv_tx_power { __s8 tx_power; } __packed; +#define HCI_MAX_AD_LENGTH 31 + +#define HCI_OP_LE_SET_ADV_DATA 0x2008 +struct hci_cp_le_set_adv_data { + __u8 length; + __u8 data[HCI_MAX_AD_LENGTH]; +} __packed; + #define HCI_OP_LE_SET_SCAN_PARAM 0x200b struct hci_cp_le_set_scan_param { __u8 type; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ce6dbeb6dfb..ef5b85dac3f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -279,6 +279,8 @@ struct hci_dev { struct le_scan_params le_scan_params; __s8 adv_tx_power; + __u8 adv_data[HCI_MAX_AD_LENGTH]; + __u8 adv_data_len; int (*open)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev); @@ -734,6 +736,8 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, u8 *randomizer); int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); +int hci_update_ad(struct hci_dev *hdev); + void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); int hci_recv_frame(struct sk_buff *skb); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9713a2917dd..e3a49db9cfc 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -594,6 +594,99 @@ done: return err; } +static u8 create_ad(struct hci_dev *hdev, u8 *ptr) +{ + u8 ad_len = 0, flags = 0; + size_t name_len; + + if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) + flags |= LE_AD_GENERAL; + + if (!lmp_bredr_capable(hdev)) + flags |= LE_AD_NO_BREDR; + + if (lmp_le_br_capable(hdev)) + flags |= LE_AD_SIM_LE_BREDR_CTRL; + + if (lmp_host_le_br_capable(hdev)) + flags |= LE_AD_SIM_LE_BREDR_HOST; + + if (flags) { + BT_DBG("adv flags 0x%02x", flags); + + ptr[0] = 2; + ptr[1] = EIR_FLAGS; + ptr[2] = flags; + + ad_len += 3; + ptr += 3; + } + + if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) { + ptr[0] = 2; + ptr[1] = EIR_TX_POWER; + ptr[2] = (u8) hdev->adv_tx_power; + + ad_len += 3; + ptr += 3; + } + + name_len = strlen(hdev->dev_name); + if (name_len > 0) { + size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2; + + if (name_len > max_len) { + name_len = max_len; + ptr[1] = EIR_NAME_SHORT; + } else + ptr[1] = EIR_NAME_COMPLETE; + + ptr[0] = name_len + 1; + + memcpy(ptr + 2, hdev->dev_name, name_len); + + ad_len += (name_len + 2); + ptr += (name_len + 2); + } + + return ad_len; +} + +int hci_update_ad(struct hci_dev *hdev) +{ + struct hci_cp_le_set_adv_data cp; + u8 len; + int err; + + hci_dev_lock(hdev); + + if (!lmp_le_capable(hdev)) { + err = -EINVAL; + goto unlock; + } + + memset(&cp, 0, sizeof(cp)); + + len = create_ad(hdev, cp.data); + + if (hdev->adv_data_len == len && + memcmp(cp.data, hdev->adv_data, len) == 0) { + err = 0; + goto unlock; + } + + memcpy(hdev->adv_data, cp.data, sizeof(cp.data)); + hdev->adv_data_len = len; + + cp.length = len; + err = hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); + +unlock: + hci_dev_unlock(hdev); + + return err; +} + /* ---- HCI ioctl helpers ---- */ int hci_dev_open(__u16 dev) @@ -651,6 +744,7 @@ int hci_dev_open(__u16 dev) hci_dev_hold(hdev); set_bit(HCI_UP, &hdev->flags); hci_notify(hdev, HCI_DEV_UP); + hci_update_ad(hdev); if (!test_bit(HCI_SETUP, &hdev->dev_flags) && mgmt_valid_hdev(hdev)) { hci_dev_lock(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 09c65712e8c..7caea1af557 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -204,6 +204,9 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) hdev->discovery.state = DISCOVERY_STOPPED; hdev->inq_tx_power = HCI_TX_POWER_INVALID; hdev->adv_tx_power = HCI_TX_POWER_INVALID; + + memset(hdev->adv_data, 0, sizeof(hdev->adv_data)); + hdev->adv_data_len = 0; } static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) @@ -226,6 +229,9 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_unlock(hdev); + if (!status && !test_bit(HCI_INIT, &hdev->flags)) + hci_update_ad(hdev); + hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status); } @@ -1091,8 +1097,11 @@ static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - if (!rp->status) + if (!rp->status) { hdev->adv_tx_power = rp->tx_power; + if (!test_bit(HCI_INIT, &hdev->flags)) + hci_update_ad(hdev); + } hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status); } From c1d5dc4ac15be45c7061e207f06ad8dfba0c2170 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 8 Nov 2012 01:23:01 +0100 Subject: [PATCH 03/15] Bluetooth: Fix updating advertising state flags and data This patch adds a callback for the HCI_LE_Set_Advertise_Enable command. The callback is responsible for updating the HCI_LE_PERIPHERAL flag updating as well as updating the advertising data flags field to indicate undirected connectable advertising. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci.h | 2 ++ net/bluetooth/hci_event.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 7306078e547..4bbabd85f5e 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -957,6 +957,8 @@ struct hci_cp_le_set_adv_data { __u8 data[HCI_MAX_AD_LENGTH]; } __packed; +#define HCI_OP_LE_SET_ADV_ENABLE 0x200a + #define HCI_OP_LE_SET_SCAN_PARAM 0x200b struct hci_cp_le_set_scan_param { __u8 type; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 7caea1af557..9f5c5f24450 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1190,6 +1190,33 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev, hci_dev_unlock(hdev); } +static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) +{ + __u8 *sent, status = *((__u8 *) skb->data); + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_ENABLE); + if (!sent) + return; + + hci_dev_lock(hdev); + + if (!status) { + if (*sent) + set_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags); + else + clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags); + } + + hci_dev_unlock(hdev); + + if (!test_bit(HCI_INIT, &hdev->flags)) + hci_update_ad(hdev); + + hci_req_complete(hdev, HCI_OP_LE_SET_ADV_ENABLE, status); +} + static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); @@ -2585,6 +2612,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cc_le_set_scan_param(hdev, skb); break; + case HCI_OP_LE_SET_ADV_ENABLE: + hci_cc_le_set_adv_enable(hdev, skb); + break; + case HCI_OP_LE_SET_SCAN_ENABLE: hci_cc_le_set_scan_enable(hdev, skb); break; From 96eff46e9f5632efa0d2941f7e028701a5f1a0f6 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 15 Nov 2012 18:14:53 +0200 Subject: [PATCH 04/15] Bluetooth: Use __l2cap_no_conn_pending helper Use helper instead of test_bit. This is the only place left using test CONF_CONNECT_PEND flag. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a1faaab4183..4479894e0a5 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -6380,7 +6380,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) continue; } - if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) { + if (!__l2cap_no_conn_pending(chan)) { l2cap_chan_unlock(chan); continue; } From 522db70286fcce420e5fc1be107912fbd3806323 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 15 Nov 2012 18:14:55 +0200 Subject: [PATCH 05/15] Bluetooth: Remove unneeded local_amp_id initialization local_amp_id is already set in l2cap_connect() which is called several lines above. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4479894e0a5..e4f52a7f08c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4284,7 +4284,6 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn, BT_DBG("mgr %p bredr_chan %p hs_hcon %p", mgr, chan, hs_hcon); - chan->local_amp_id = req->amp_id; mgr->bredr_chan = chan; chan->hs_hcon = hs_hcon; conn->mtu = hdev->block_mtu; From a514b17fab51c1433db920d76cf8ddda959e5da0 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 14 Nov 2012 17:39:30 +0200 Subject: [PATCH 06/15] Bluetooth: Refactor locking in amp_physical_cfm Remove locking from l2cap_physical_cfm and lock chan inside amp_physical_cfm. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/amp.c | 6 +++++- net/bluetooth/l2cap_core.c | 7 ++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d65db459c84..f57fab04e7c 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -811,6 +811,6 @@ void l2cap_send_conn_req(struct l2cap_chan *chan); void l2cap_move_start(struct l2cap_chan *chan); void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, u8 status); -void l2cap_physical_cfm(struct l2cap_chan *chan, int result); +void __l2cap_physical_cfm(struct l2cap_chan *chan, int result); #endif /* __L2CAP_H */ diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 4b2fea6c1c2..eaf473ffeef 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -386,13 +386,17 @@ void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon) bredr_chan = mgr->bredr_chan; + l2cap_chan_lock(bredr_chan); + set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags); bredr_chan->remote_amp_id = hs_hcon->remote_id; bredr_chan->hs_hcon = hs_hcon; bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu; bredr_chan->fcs = L2CAP_FCS_NONE; - l2cap_physical_cfm(bredr_chan, 0); + __l2cap_physical_cfm(bredr_chan, 0); + + l2cap_chan_unlock(bredr_chan); hci_dev_put(bredr_hdev); } diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index e4f52a7f08c..22c4ef926b0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4611,7 +4611,8 @@ static void l2cap_do_move_cancel(struct l2cap_chan *chan, int result) l2cap_ertm_send(chan); } -void l2cap_physical_cfm(struct l2cap_chan *chan, int result) +/* Invoke with locked chan */ +void __l2cap_physical_cfm(struct l2cap_chan *chan, int result) { u8 local_amp_id = chan->local_amp_id; u8 remote_amp_id = chan->remote_amp_id; @@ -4619,8 +4620,6 @@ void l2cap_physical_cfm(struct l2cap_chan *chan, int result) BT_DBG("chan %p, result %d, local_amp_id %d, remote_amp_id %d", chan, result, local_amp_id, remote_amp_id); - l2cap_chan_lock(chan); - if (chan->state == BT_DISCONN || chan->state == BT_CLOSED) { l2cap_chan_unlock(chan); return; @@ -4644,8 +4643,6 @@ void l2cap_physical_cfm(struct l2cap_chan *chan, int result) break; } } - - l2cap_chan_unlock(chan); } static inline int l2cap_move_channel_req(struct l2cap_conn *conn, From 12d6cc60f2d02d5754ca662b414f8f96200b14a6 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 14 Nov 2012 17:39:31 +0200 Subject: [PATCH 07/15] Bluetooth: Disable FCS only for new HS channels Set chan->fcs to L2CAP_FCS_NONE only for new L2CAP channels (not moved). Other side can still request to use FCS. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/amp.c | 1 - net/bluetooth/l2cap_core.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index eaf473ffeef..0258b2645ed 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -392,7 +392,6 @@ void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon) bredr_chan->remote_amp_id = hs_hcon->remote_id; bredr_chan->hs_hcon = hs_hcon; bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu; - bredr_chan->fcs = L2CAP_FCS_NONE; __l2cap_physical_cfm(bredr_chan, 0); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 22c4ef926b0..fc92fe34111 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4517,6 +4517,8 @@ void l2cap_move_start(struct l2cap_chan *chan) static void l2cap_do_create(struct l2cap_chan *chan, int result, u8 local_amp_id, u8 remote_amp_id) { + chan->fcs = L2CAP_FCS_NONE; + if (!test_bit(CONF_CONNECT_PEND, &chan->conf_state)) { struct l2cap_conn_rsp rsp; char buf[128]; From 62cd50e262182685c291bc86076e74ef6f7331b1 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 14 Nov 2012 17:39:32 +0200 Subject: [PATCH 08/15] Bluetooth: trivial: Use __constant for constants Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index fc92fe34111..3ed93938370 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4528,12 +4528,12 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result, /* Incoming channel on AMP */ if (result == L2CAP_CR_SUCCESS) { /* Send successful response */ - rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); - rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); + rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); + rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); } else { /* Send negative response */ - rsp.result = cpu_to_le16(L2CAP_CR_NO_MEM); - rsp.status = cpu_to_le16(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(chan->conn, chan->ident, L2CAP_CREATE_CHAN_RSP, From 1ee3ff6110c16acfc915a79b1e3feb5013c41e75 Mon Sep 17 00:00:00 2001 From: Jeff Cook Date: Fri, 9 Nov 2012 16:39:48 -0700 Subject: [PATCH 09/15] Bluetooth: Add support for BCM20702A0 [0b05, 17b5] Vendor-specific ID for BCM20702A0. Support for bluetooth over Asus Wi-Fi GO!, included with Asus P8Z77-V Deluxe. T: Bus=07 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0b05 ProdID=17b5 Rev=01.12 S: Manufacturer=Broadcom Corp S: Product=BCM20702A0 S: SerialNumber=94DBC98AC113 C: #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=0mA I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none) I: If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none) I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) I: If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none) Cc: stable@vger.kernel.org Signed-off-by: Jeff Cook Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btusb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index debda27df9b..5693b9b3147 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -96,6 +96,7 @@ static struct usb_device_id btusb_table[] = { { USB_DEVICE(0x0c10, 0x0000) }, /* Broadcom BCM20702A0 */ + { USB_DEVICE(0x0b05, 0x17b5) }, { USB_DEVICE(0x04ca, 0x2003) }, { USB_DEVICE(0x0489, 0xe042) }, { USB_DEVICE(0x413c, 0x8197) }, From d1244adc4281eb983a7f41b753164233a7b16b55 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 12 Nov 2012 11:01:05 +0100 Subject: [PATCH 10/15] Bluetooth: Increase HCI command tx timeout Read Local OOB Data command can take more than 1 second on some chips. e.g. on CSR 0a12:0001 first call to Read Local OOB Data after reset takes about 1300ms resulting in tx timeout error. [27698.368655] Bluetooth: hci0 command 0x0c57 tx timeout 2012-10-31 15:53:36.178585 < HCI Command: Read Local OOB Data (0x03|0x0057) plen 0 2012-10-31 15:53:37.496996 > HCI Event: Command Complete (0x0e) plen 36 Read Local OOB Data (0x03|0x0057) ncmd 1 status 0x00 hash 0x92219d9b447f2aa9dc12dda2ae7bae6a randomizer 0xb1948d0febe4ea38ce85c4e66313beba Signed-off-by: Szymon Janc Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 4bbabd85f5e..45eee08157b 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -154,7 +154,7 @@ enum { #define HCI_DISCONN_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ #define HCI_PAIRING_TIMEOUT msecs_to_jiffies(60000) /* 60 seconds */ #define HCI_INIT_TIMEOUT msecs_to_jiffies(10000) /* 10 seconds */ -#define HCI_CMD_TIMEOUT msecs_to_jiffies(1000) /* 1 second */ +#define HCI_CMD_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ #define HCI_ACL_TX_TIMEOUT msecs_to_jiffies(45000) /* 45 seconds */ #define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ From 62748ca16f2f79a62d90fb45963233fb10f726c4 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 20 Nov 2012 17:16:19 +0200 Subject: [PATCH 11/15] Bluetooth: Fix sending L2CAP Create Chan Req When receiving Physical Link Completed event we need to create L2CAP channel with L2CAP Create Chan Request. Current code was sending this command only if connection was pending (which is probably needed in channel move case). If channel is not moved but created Create Chan should be sent for outgoing channel which is checked with BT_CONNECT flag. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3ed93938370..7114bdff595 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4517,15 +4517,31 @@ void l2cap_move_start(struct l2cap_chan *chan) static void l2cap_do_create(struct l2cap_chan *chan, int result, u8 local_amp_id, u8 remote_amp_id) { + BT_DBG("chan %p state %s %u -> %u", chan, state_to_string(chan->state), + local_amp_id, remote_amp_id); + chan->fcs = L2CAP_FCS_NONE; - if (!test_bit(CONF_CONNECT_PEND, &chan->conf_state)) { + /* Outgoing channel on AMP */ + if (chan->state == BT_CONNECT) { + if (result == L2CAP_CR_SUCCESS) { + chan->local_amp_id = local_amp_id; + l2cap_send_create_chan_req(chan, remote_amp_id); + } else { + /* Revert to BR/EDR connect */ + l2cap_send_conn_req(chan); + } + + return; + } + + /* Incoming channel on AMP */ + if (__l2cap_no_conn_pending(chan)) { struct l2cap_conn_rsp rsp; char buf[128]; rsp.scid = cpu_to_le16(chan->dcid); rsp.dcid = cpu_to_le16(chan->scid); - /* Incoming channel on AMP */ if (result == L2CAP_CR_SUCCESS) { /* Send successful response */ rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); @@ -4547,15 +4563,6 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result, l2cap_build_conf_req(chan, buf), buf); chan->num_conf_req++; } - } else { - /* Outgoing channel on AMP */ - if (result == L2CAP_CR_SUCCESS) { - chan->local_amp_id = local_amp_id; - l2cap_send_create_chan_req(chan, remote_amp_id); - } else { - /* Revert to BR/EDR connect */ - l2cap_send_conn_req(chan); - } } } From 37295996ce181a2a4e74308070abf06bd822f7a1 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 20 Nov 2012 17:16:20 +0200 Subject: [PATCH 12/15] Bluetooth: Set local_amp_id after getting Phylink Completed evt local_amp_id is used in l2cap_physical_cfm and shall be set up before calling it. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/amp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 0258b2645ed..1b0d92c0643 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -390,6 +390,7 @@ void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon) set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags); bredr_chan->remote_amp_id = hs_hcon->remote_id; + bredr_chan->local_amp_id = hs_hcon->hdev->id; bredr_chan->hs_hcon = hs_hcon; bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu; From 1bb166e66cc46323d3757ce1027cc1c767498d50 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 20 Nov 2012 17:16:21 +0200 Subject: [PATCH 13/15] Bluetooth: Improve error message printing Instead of printing: "[ 7763.082007] Bluetooth: 2" print something like: "[ 7763.082007] Bluetooth: Trailing bytes: 2 in sframe" Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7114bdff595..f44c5429b4f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -6091,7 +6091,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) control->super); if (len != 0) { - BT_ERR("%d", len); + BT_ERR("Trailing bytes: %d in sframe", len); l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } From fd45bf4c923308b19d8baa3c227d26a0e7d79fa7 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 20 Nov 2012 17:16:22 +0200 Subject: [PATCH 14/15] Bluetooth: AMP: Set no FCS for incoming L2CAP chan When receiving L2CAP Create Channel Request set the channel as L2CAP_FCS_NONE. Then in "L2CAP Config req" following field will be set: "FCS Option 0x00 (No FCS)". So by default High Speed channels have no FCS. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index f44c5429b4f..b52f66d2243 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4286,6 +4286,7 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn, mgr->bredr_chan = chan; chan->hs_hcon = hs_hcon; + chan->fcs = L2CAP_FCS_NONE; conn->mtu = hdev->block_mtu; } From 2b2fec4d08a0aabe20d2e749cb7978f04217af65 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 20 Nov 2012 11:38:54 +0100 Subject: [PATCH 15/15] Bluetooth: Remove OOB data if device was discovered in band OOB authentication mechanism should be used only if pairing process has been activated by previous OOB information exchange (Core Spec 4.0 , vol. 1, Part A, 5.1.4.3). Stored OOB data for specific device should be removed if that device was discovered in band later on. Signed-off-by: Szymon Janc Acked-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- net/bluetooth/hci_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e3a49db9cfc..81f4bac098c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -434,6 +434,8 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, BT_DBG("cache %p, %pMR", cache, &data->bdaddr); + hci_remove_remote_oob_data(hdev, &data->bdaddr); + if (ssp) *ssp = data->ssp_mode;