Commit 0006433a authored by John W. Linville's avatar John W. Linville

Merge branch 'for-upstream' of...

Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
parents bb0f8609 22e70786
...@@ -59,6 +59,8 @@ struct btmrvl_device { ...@@ -59,6 +59,8 @@ struct btmrvl_device {
}; };
struct btmrvl_adapter { struct btmrvl_adapter {
void *hw_regs_buf;
u8 *hw_regs;
u32 int_count; u32 int_count;
struct sk_buff_head tx_queue; struct sk_buff_head tx_queue;
u8 psmode; u8 psmode;
...@@ -140,7 +142,7 @@ void btmrvl_interrupt(struct btmrvl_private *priv); ...@@ -140,7 +142,7 @@ void btmrvl_interrupt(struct btmrvl_private *priv);
bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb); bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);
int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb); int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb);
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd); int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd);
int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv); int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv);
int btmrvl_enable_ps(struct btmrvl_private *priv); int btmrvl_enable_ps(struct btmrvl_private *priv);
int btmrvl_prepare_command(struct btmrvl_private *priv); int btmrvl_prepare_command(struct btmrvl_private *priv);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#include "btmrvl_drv.h" #include "btmrvl_drv.h"
#include "btmrvl_sdio.h"
#define VERSION "1.0" #define VERSION "1.0"
...@@ -201,7 +202,7 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode, ...@@ -201,7 +202,7 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode,
return 0; return 0;
} }
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd)
{ {
int ret; int ret;
...@@ -337,10 +338,25 @@ static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb) ...@@ -337,10 +338,25 @@ static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb)
static void btmrvl_init_adapter(struct btmrvl_private *priv) static void btmrvl_init_adapter(struct btmrvl_private *priv)
{ {
int buf_size;
skb_queue_head_init(&priv->adapter->tx_queue); skb_queue_head_init(&priv->adapter->tx_queue);
priv->adapter->ps_state = PS_AWAKE; priv->adapter->ps_state = PS_AWAKE;
buf_size = ALIGN_SZ(SDIO_BLOCK_SIZE, BTSDIO_DMA_ALIGN);
priv->adapter->hw_regs_buf = kzalloc(buf_size, GFP_KERNEL);
if (!priv->adapter->hw_regs_buf) {
priv->adapter->hw_regs = NULL;
BT_ERR("Unable to allocate buffer for hw_regs.");
} else {
priv->adapter->hw_regs =
(u8 *)ALIGN_ADDR(priv->adapter->hw_regs_buf,
BTSDIO_DMA_ALIGN);
BT_DBG("hw_regs_buf=%p hw_regs=%p",
priv->adapter->hw_regs_buf, priv->adapter->hw_regs);
}
init_waitqueue_head(&priv->adapter->cmd_wait_q); init_waitqueue_head(&priv->adapter->cmd_wait_q);
} }
...@@ -348,6 +364,7 @@ static void btmrvl_free_adapter(struct btmrvl_private *priv) ...@@ -348,6 +364,7 @@ static void btmrvl_free_adapter(struct btmrvl_private *priv)
{ {
skb_queue_purge(&priv->adapter->tx_queue); skb_queue_purge(&priv->adapter->tx_queue);
kfree(priv->adapter->hw_regs_buf);
kfree(priv->adapter); kfree(priv->adapter);
priv->adapter = NULL; priv->adapter = NULL;
......
...@@ -64,6 +64,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = { ...@@ -64,6 +64,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = {
.io_port_0 = 0x00, .io_port_0 = 0x00,
.io_port_1 = 0x01, .io_port_1 = 0x01,
.io_port_2 = 0x02, .io_port_2 = 0x02,
.int_read_to_clear = false,
}; };
static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
.cfg = 0x00, .cfg = 0x00,
...@@ -80,6 +81,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { ...@@ -80,6 +81,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
.io_port_0 = 0x78, .io_port_0 = 0x78,
.io_port_1 = 0x79, .io_port_1 = 0x79,
.io_port_2 = 0x7a, .io_port_2 = 0x7a,
.int_read_to_clear = false,
}; };
static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = { static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
...@@ -97,6 +99,9 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = { ...@@ -97,6 +99,9 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
.io_port_0 = 0xd8, .io_port_0 = 0xd8,
.io_port_1 = 0xd9, .io_port_1 = 0xd9,
.io_port_2 = 0xda, .io_port_2 = 0xda,
.int_read_to_clear = true,
.host_int_rsr = 0x01,
.card_misc_cfg = 0xcc,
}; };
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
...@@ -667,46 +672,78 @@ static int btmrvl_sdio_process_int_status(struct btmrvl_private *priv) ...@@ -667,46 +672,78 @@ static int btmrvl_sdio_process_int_status(struct btmrvl_private *priv)
return 0; return 0;
} }
static void btmrvl_sdio_interrupt(struct sdio_func *func) static int btmrvl_sdio_read_to_clear(struct btmrvl_sdio_card *card, u8 *ireg)
{ {
struct btmrvl_private *priv; struct btmrvl_adapter *adapter = card->priv->adapter;
struct btmrvl_sdio_card *card;
ulong flags;
u8 ireg = 0;
int ret; int ret;
card = sdio_get_drvdata(func); ret = sdio_readsb(card->func, adapter->hw_regs, 0, SDIO_BLOCK_SIZE);
if (!card || !card->priv) { if (ret) {
BT_ERR("sbi_interrupt(%p) card or priv is " BT_ERR("sdio_readsb: read int hw_regs failed: %d", ret);
"NULL, card=%p\n", func, card); return ret;
return;
} }
priv = card->priv; *ireg = adapter->hw_regs[card->reg->host_intstatus];
BT_DBG("hw_regs[%#x]=%#x", card->reg->host_intstatus, *ireg);
return 0;
}
ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret); static int btmrvl_sdio_write_to_clear(struct btmrvl_sdio_card *card, u8 *ireg)
{
int ret;
*ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret);
if (ret) { if (ret) {
BT_ERR("sdio_readb: read int status register failed"); BT_ERR("sdio_readb: read int status failed: %d", ret);
return; return ret;
} }
if (ireg != 0) { if (*ireg) {
/* /*
* DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
* Clear the interrupt status register and re-enable the * Clear the interrupt status register and re-enable the
* interrupt. * interrupt.
*/ */
BT_DBG("ireg = 0x%x", ireg); BT_DBG("int_status = 0x%x", *ireg);
sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS | sdio_writeb(card->func, ~(*ireg) & (DN_LD_HOST_INT_STATUS |
UP_LD_HOST_INT_STATUS), UP_LD_HOST_INT_STATUS),
card->reg->host_intstatus, &ret); card->reg->host_intstatus, &ret);
if (ret) { if (ret) {
BT_ERR("sdio_writeb: clear int status register failed"); BT_ERR("sdio_writeb: clear int status failed: %d", ret);
return; return ret;
} }
} }
return 0;
}
static void btmrvl_sdio_interrupt(struct sdio_func *func)
{
struct btmrvl_private *priv;
struct btmrvl_sdio_card *card;
ulong flags;
u8 ireg = 0;
int ret;
card = sdio_get_drvdata(func);
if (!card || !card->priv) {
BT_ERR("sbi_interrupt(%p) card or priv is "
"NULL, card=%p\n", func, card);
return;
}
priv = card->priv;
if (card->reg->int_read_to_clear)
ret = btmrvl_sdio_read_to_clear(card, &ireg);
else
ret = btmrvl_sdio_write_to_clear(card, &ireg);
if (ret)
return;
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
sdio_ireg |= ireg; sdio_ireg |= ireg;
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
...@@ -777,6 +814,30 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) ...@@ -777,6 +814,30 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
BT_DBG("SDIO FUNC%d IO port: 0x%x", func->num, card->ioport); BT_DBG("SDIO FUNC%d IO port: 0x%x", func->num, card->ioport);
if (card->reg->int_read_to_clear) {
reg = sdio_readb(func, card->reg->host_int_rsr, &ret);
if (ret < 0) {
ret = -EIO;
goto release_irq;
}
sdio_writeb(func, reg | 0x3f, card->reg->host_int_rsr, &ret);
if (ret < 0) {
ret = -EIO;
goto release_irq;
}
reg = sdio_readb(func, card->reg->card_misc_cfg, &ret);
if (ret < 0) {
ret = -EIO;
goto release_irq;
}
sdio_writeb(func, reg | 0x10, card->reg->card_misc_cfg, &ret);
if (ret < 0) {
ret = -EIO;
goto release_irq;
}
}
sdio_set_drvdata(func, card); sdio_set_drvdata(func, card);
sdio_release_host(func); sdio_release_host(func);
......
...@@ -78,6 +78,9 @@ struct btmrvl_sdio_card_reg { ...@@ -78,6 +78,9 @@ struct btmrvl_sdio_card_reg {
u8 io_port_0; u8 io_port_0;
u8 io_port_1; u8 io_port_1;
u8 io_port_2; u8 io_port_2;
bool int_read_to_clear;
u8 host_int_rsr;
u8 card_misc_cfg;
}; };
struct btmrvl_sdio_card { struct btmrvl_sdio_card {
......
...@@ -55,13 +55,6 @@ struct h4_struct { ...@@ -55,13 +55,6 @@ struct h4_struct {
struct sk_buff_head txq; struct sk_buff_head txq;
}; };
/* H4 receiver States */
#define H4_W4_PACKET_TYPE 0
#define H4_W4_EVENT_HDR 1
#define H4_W4_ACL_HDR 2
#define H4_W4_SCO_HDR 3
#define H4_W4_DATA 4
/* Initialize protocol */ /* Initialize protocol */
static int h4_open(struct hci_uart *hu) static int h4_open(struct hci_uart *hu)
{ {
......
...@@ -367,6 +367,7 @@ enum { ...@@ -367,6 +367,7 @@ enum {
#define HCI_ERROR_REMOTE_POWER_OFF 0x15 #define HCI_ERROR_REMOTE_POWER_OFF 0x15
#define HCI_ERROR_LOCAL_HOST_TERM 0x16 #define HCI_ERROR_LOCAL_HOST_TERM 0x16
#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18 #define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18
#define HCI_ERROR_ADVERTISING_TIMEOUT 0x3c
/* Flow control modes */ /* Flow control modes */
#define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00 #define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00
......
...@@ -68,6 +68,11 @@ struct discovery_state { ...@@ -68,6 +68,11 @@ struct discovery_state {
struct list_head unknown; /* Name state not known */ struct list_head unknown; /* Name state not known */
struct list_head resolve; /* Name needs to be resolved */ struct list_head resolve; /* Name needs to be resolved */
__u32 timestamp; __u32 timestamp;
bdaddr_t last_adv_addr;
u8 last_adv_addr_type;
s8 last_adv_rssi;
u8 last_adv_data[HCI_MAX_AD_LENGTH];
u8 last_adv_data_len;
}; };
struct hci_conn_hash { struct hci_conn_hash {
...@@ -194,6 +199,7 @@ struct hci_dev { ...@@ -194,6 +199,7 @@ struct hci_dev {
__u16 le_scan_window; __u16 le_scan_window;
__u16 le_conn_min_interval; __u16 le_conn_min_interval;
__u16 le_conn_max_interval; __u16 le_conn_max_interval;
__u16 discov_interleaved_timeout;
__u8 ssp_debug_mode; __u8 ssp_debug_mode;
__u16 devid_source; __u16 devid_source;
...@@ -1204,8 +1210,8 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event); ...@@ -1204,8 +1210,8 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event);
*/ */
#define DISCOV_LE_SCAN_WIN 0x12 #define DISCOV_LE_SCAN_WIN 0x12
#define DISCOV_LE_SCAN_INT 0x12 #define DISCOV_LE_SCAN_INT 0x12
#define DISCOV_LE_TIMEOUT msecs_to_jiffies(10240) #define DISCOV_LE_TIMEOUT 10240 /* msec */
#define DISCOV_INTERLEAVED_TIMEOUT msecs_to_jiffies(5120) #define DISCOV_INTERLEAVED_TIMEOUT 5120 /* msec */
#define DISCOV_INTERLEAVED_INQUIRY_LEN 0x04 #define DISCOV_INTERLEAVED_INQUIRY_LEN 0x04
#define DISCOV_BREDR_INQUIRY_LEN 0x08 #define DISCOV_BREDR_INQUIRY_LEN 0x08
...@@ -1265,7 +1271,8 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192, ...@@ -1265,7 +1271,8 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
u8 *randomizer256, u8 status); u8 *randomizer256, u8 status);
void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name,
u8 ssp, u8 *eir, u16 eir_len); u8 ssp, u8 *eir, u16 eir_len, u8 *scan_rsp,
u8 scan_rsp_len);
void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, s8 rssi, u8 *name, u8 name_len); u8 addr_type, s8 rssi, u8 *name, u8 name_len);
void mgmt_discovering(struct hci_dev *hdev, u8 discovering); void mgmt_discovering(struct hci_dev *hdev, u8 discovering);
......
...@@ -367,9 +367,23 @@ static void le_conn_timeout(struct work_struct *work) ...@@ -367,9 +367,23 @@ static void le_conn_timeout(struct work_struct *work)
{ {
struct hci_conn *conn = container_of(work, struct hci_conn, struct hci_conn *conn = container_of(work, struct hci_conn,
le_conn_timeout.work); le_conn_timeout.work);
struct hci_dev *hdev = conn->hdev;
BT_DBG(""); BT_DBG("");
/* We could end up here due to having done directed advertising,
* so clean up the state if necessary. This should however only
* happen with broken hardware or if low duty cycle was used
* (which doesn't have a timeout of its own).
*/
if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
u8 enable = 0x00;
hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable),
&enable);
hci_le_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT);
return;
}
hci_le_create_connection_cancel(conn); hci_le_create_connection_cancel(conn);
} }
...@@ -401,6 +415,10 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) ...@@ -401,6 +415,10 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
case ACL_LINK: case ACL_LINK:
conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
break; break;
case LE_LINK:
/* conn->src should reflect the local identity address */
hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
break;
case SCO_LINK: case SCO_LINK:
if (lmp_esco_capable(hdev)) if (lmp_esco_capable(hdev))
conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) | conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
...@@ -545,6 +563,11 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status) ...@@ -545,6 +563,11 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
* favor of connection establishment, we should restart it. * favor of connection establishment, we should restart it.
*/ */
hci_update_background_scan(hdev); hci_update_background_scan(hdev);
/* Re-enable advertising in case this was a failed connection
* attempt as a peripheral.
*/
mgmt_reenable_advertising(hdev);
} }
static void create_le_conn_complete(struct hci_dev *hdev, u8 status) static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
...@@ -605,6 +628,45 @@ static void hci_req_add_le_create_conn(struct hci_request *req, ...@@ -605,6 +628,45 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
conn->state = BT_CONNECT; conn->state = BT_CONNECT;
} }
static void hci_req_directed_advertising(struct hci_request *req,
struct hci_conn *conn)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_adv_param cp;
u8 own_addr_type;
u8 enable;
enable = 0x00;
hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
/* Clear the HCI_ADVERTISING bit temporarily so that the
* hci_update_random_address knows that it's safe to go ahead
* and write a new random address. The flag will be set back on
* as soon as the SET_ADV_ENABLE HCI command completes.
*/
clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
/* Set require_privacy to false so that the remote device has a
* chance of identifying us.
*/
if (hci_update_random_address(req, false, &own_addr_type) < 0)
return;
memset(&cp, 0, sizeof(cp));
cp.type = LE_ADV_DIRECT_IND;
cp.own_address_type = own_addr_type;
cp.direct_addr_type = conn->dst_type;
bacpy(&cp.direct_addr, &conn->dst);
cp.channel_map = hdev->le_adv_channel_map;
hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
enable = 0x01;
hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
conn->state = BT_CONNECT;
}
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, u8 sec_level, u8 auth_type) u8 dst_type, u8 sec_level, u8 auth_type)
{ {
...@@ -614,9 +676,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, ...@@ -614,9 +676,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
struct hci_request req; struct hci_request req;
int err; int err;
if (test_bit(HCI_ADVERTISING, &hdev->flags))
return ERR_PTR(-ENOTSUPP);
/* Some devices send ATT messages as soon as the physical link is /* Some devices send ATT messages as soon as the physical link is
* established. To be able to handle these ATT messages, the user- * established. To be able to handle these ATT messages, the user-
* space first establishes the connection and then starts the pairing * space first establishes the connection and then starts the pairing
...@@ -664,13 +723,20 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, ...@@ -664,13 +723,20 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
conn->dst_type = dst_type; conn->dst_type = dst_type;
conn->out = true;
conn->link_mode |= HCI_LM_MASTER;
conn->sec_level = BT_SECURITY_LOW; conn->sec_level = BT_SECURITY_LOW;
conn->pending_sec_level = sec_level; conn->pending_sec_level = sec_level;
conn->auth_type = auth_type; conn->auth_type = auth_type;
hci_req_init(&req, hdev);
if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
hci_req_directed_advertising(&req, conn);
goto create_conn;
}
conn->out = true;
conn->link_mode |= HCI_LM_MASTER;
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
if (params) { if (params) {
conn->le_conn_min_interval = params->conn_min_interval; conn->le_conn_min_interval = params->conn_min_interval;
...@@ -680,8 +746,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, ...@@ -680,8 +746,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
conn->le_conn_max_interval = hdev->le_conn_max_interval; conn->le_conn_max_interval = hdev->le_conn_max_interval;
} }
hci_req_init(&req, hdev);
/* If controller is scanning, we stop it since some controllers are /* If controller is scanning, we stop it since some controllers are
* not able to scan and connect at the same time. Also set the * not able to scan and connect at the same time. Also set the
* HCI_LE_SCAN_INTERRUPTED flag so that the command complete * HCI_LE_SCAN_INTERRUPTED flag so that the command complete
...@@ -695,6 +759,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, ...@@ -695,6 +759,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
hci_req_add_le_create_conn(&req, conn); hci_req_add_le_create_conn(&req, conn);
create_conn:
err = hci_req_run(&req, create_le_conn_complete); err = hci_req_run(&req, create_le_conn_complete);
if (err) { if (err) {
hci_conn_del(conn); hci_conn_del(conn);
......
...@@ -955,14 +955,9 @@ static ssize_t le_auto_conn_write(struct file *file, const char __user *data, ...@@ -955,14 +955,9 @@ static ssize_t le_auto_conn_write(struct file *file, const char __user *data,
if (count < 3) if (count < 3)
return -EINVAL; return -EINVAL;
buf = kzalloc(count, GFP_KERNEL); buf = memdup_user(data, count);
if (!buf) if (IS_ERR(buf))
return -ENOMEM; return PTR_ERR(buf);
if (copy_from_user(buf, data, count)) {
err = -EFAULT;
goto done;
}
if (memcmp(buf, "add", 3) == 0) { if (memcmp(buf, "add", 3) == 0) {
n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu %hhu", n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu %hhu",
...@@ -1828,6 +1823,9 @@ static int __hci_init(struct hci_dev *hdev) ...@@ -1828,6 +1823,9 @@ static int __hci_init(struct hci_dev *hdev)
&lowpan_debugfs_fops); &lowpan_debugfs_fops);
debugfs_create_file("le_auto_conn", 0644, hdev->debugfs, hdev, debugfs_create_file("le_auto_conn", 0644, hdev->debugfs, hdev,
&le_auto_conn_fops); &le_auto_conn_fops);
debugfs_create_u16("discov_interleaved_timeout", 0644,
hdev->debugfs,
&hdev->discov_interleaved_timeout);
} }
return 0; return 0;
...@@ -2033,12 +2031,11 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, ...@@ -2033,12 +2031,11 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
hci_remove_remote_oob_data(hdev, &data->bdaddr); hci_remove_remote_oob_data(hdev, &data->bdaddr);
if (ssp) *ssp = data->ssp_mode;
*ssp = data->ssp_mode;
ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr); ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr);
if (ie) { if (ie) {
if (ie->data.ssp_mode && ssp) if (ie->data.ssp_mode)
*ssp = true; *ssp = true;
if (ie->name_state == NAME_NEEDED && if (ie->name_state == NAME_NEEDED &&
...@@ -3791,6 +3788,7 @@ struct hci_dev *hci_alloc_dev(void) ...@@ -3791,6 +3788,7 @@ struct hci_dev *hci_alloc_dev(void)
hdev->le_conn_max_interval = 0x0038; hdev->le_conn_max_interval = 0x0038;
hdev->rpa_timeout = HCI_DEFAULT_RPA_TIMEOUT; hdev->rpa_timeout = HCI_DEFAULT_RPA_TIMEOUT;
hdev->discov_interleaved_timeout = DISCOV_INTERLEAVED_TIMEOUT;
mutex_init(&hdev->lock); mutex_init(&hdev->lock);
mutex_init(&hdev->req_lock); mutex_init(&hdev->req_lock);
......
This diff is collapsed.
...@@ -524,16 +524,7 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, ...@@ -524,16 +524,7 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd,
case HCISETRAW: case HCISETRAW:
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
return -EOPNOTSUPP;
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
return -EPERM;
if (arg)
set_bit(HCI_RAW, &hdev->flags);
else
clear_bit(HCI_RAW, &hdev->flags);
return 0;
case HCIGETCONNINFO: case HCIGETCONNINFO:
return hci_get_conn_info(hdev, (void __user *) arg); return hci_get_conn_info(hdev, (void __user *) arg);
......
...@@ -58,6 +58,7 @@ int bt_to_errno(__u16 code) ...@@ -58,6 +58,7 @@ int bt_to_errno(__u16 code)
return EIO; return EIO;
case 0x04: case 0x04:
case 0x3c:
return EHOSTDOWN; return EHOSTDOWN;
case 0x05: case 0x05:
......
...@@ -2850,10 +2850,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -2850,10 +2850,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
} }
sec_level = BT_SECURITY_MEDIUM; sec_level = BT_SECURITY_MEDIUM;
if (cp->io_cap == 0x03) auth_type = HCI_AT_DEDICATED_BONDING;
auth_type = HCI_AT_DEDICATED_BONDING;
else
auth_type = HCI_AT_DEDICATED_BONDING_MITM;
if (cp->addr.type == BDADDR_BREDR) { if (cp->addr.type == BDADDR_BREDR) {
conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level, conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
...@@ -3351,6 +3348,8 @@ static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) ...@@ -3351,6 +3348,8 @@ static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
static void start_discovery_complete(struct hci_dev *hdev, u8 status) static void start_discovery_complete(struct hci_dev *hdev, u8 status)
{ {
unsigned long timeout = 0;
BT_DBG("status %d", status); BT_DBG("status %d", status);
if (status) { if (status) {
...@@ -3366,13 +3365,11 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status) ...@@ -3366,13 +3365,11 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status)
switch (hdev->discovery.type) { switch (hdev->discovery.type) {
case DISCOV_TYPE_LE: case DISCOV_TYPE_LE:
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable, timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
DISCOV_LE_TIMEOUT);
break; break;
case DISCOV_TYPE_INTERLEAVED: case DISCOV_TYPE_INTERLEAVED:
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable, timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
DISCOV_INTERLEAVED_TIMEOUT);
break; break;
case DISCOV_TYPE_BREDR: case DISCOV_TYPE_BREDR:
...@@ -3381,6 +3378,11 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status) ...@@ -3381,6 +3378,11 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status)
default: default:
BT_ERR("Invalid discovery type %d", hdev->discovery.type); BT_ERR("Invalid discovery type %d", hdev->discovery.type);
} }
if (!timeout)
return;
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable, timeout);
} }
static int start_discovery(struct sock *sk, struct hci_dev *hdev, static int start_discovery(struct sock *sk, struct hci_dev *hdev,
...@@ -5668,8 +5670,9 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192, ...@@ -5668,8 +5670,9 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
} }
void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name,
ssp, u8 *eir, u16 eir_len) u8 ssp, u8 *eir, u16 eir_len, u8 *scan_rsp,
u8 scan_rsp_len)
{ {
char buf[512]; char buf[512];
struct mgmt_ev_device_found *ev = (void *) buf; struct mgmt_ev_device_found *ev = (void *) buf;
...@@ -5679,8 +5682,10 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, ...@@ -5679,8 +5682,10 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
if (!hci_discovery_active(hdev)) if (!hci_discovery_active(hdev))
return; return;
/* Leave 5 bytes for a potential CoD field */ /* Make sure that the buffer is big enough. The 5 extra bytes
if (sizeof(*ev) + eir_len + 5 > sizeof(buf)) * are for the potential CoD field.
*/
if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
return; return;
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
...@@ -5707,8 +5712,11 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, ...@@ -5707,8 +5712,11 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
dev_class, 3); dev_class, 3);
ev->eir_len = cpu_to_le16(eir_len); if (scan_rsp_len > 0)
ev_size = sizeof(*ev) + eir_len; memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL); mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment