Commit 0d4f55bc 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 75ae83d6 4f3e219d
...@@ -30,3 +30,5 @@ hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o ...@@ -30,3 +30,5 @@ hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
hci_uart-$(CONFIG_BT_HCIUART_ATH3K) += hci_ath.o hci_uart-$(CONFIG_BT_HCIUART_ATH3K) += hci_ath.o
hci_uart-$(CONFIG_BT_HCIUART_3WIRE) += hci_h5.o hci_uart-$(CONFIG_BT_HCIUART_3WIRE) += hci_h5.o
hci_uart-objs := $(hci_uart-y) hci_uart-objs := $(hci_uart-y)
ccflags-y += -D__CHECK_ENDIAN__
...@@ -85,6 +85,7 @@ static struct usb_device_id ath3k_table[] = { ...@@ -85,6 +85,7 @@ static struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x04CA, 0x3008) }, { USB_DEVICE(0x04CA, 0x3008) },
{ USB_DEVICE(0x13d3, 0x3362) }, { USB_DEVICE(0x13d3, 0x3362) },
{ USB_DEVICE(0x0CF3, 0xE004) }, { USB_DEVICE(0x0CF3, 0xE004) },
{ USB_DEVICE(0x0CF3, 0xE005) },
{ USB_DEVICE(0x0930, 0x0219) }, { USB_DEVICE(0x0930, 0x0219) },
{ USB_DEVICE(0x0489, 0xe057) }, { USB_DEVICE(0x0489, 0xe057) },
{ USB_DEVICE(0x13d3, 0x3393) }, { USB_DEVICE(0x13d3, 0x3393) },
...@@ -126,6 +127,7 @@ static struct usb_device_id ath3k_blist_tbl[] = { ...@@ -126,6 +127,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <linux/ctype.h>
#include <linux/firmware.h>
#define BTM_HEADER_LEN 4 #define BTM_HEADER_LEN 4
#define BTM_UPLD_SIZE 2312 #define BTM_UPLD_SIZE 2312
...@@ -41,6 +43,8 @@ struct btmrvl_thread { ...@@ -41,6 +43,8 @@ struct btmrvl_thread {
struct btmrvl_device { struct btmrvl_device {
void *card; void *card;
struct hci_dev *hcidev; struct hci_dev *hcidev;
struct device *dev;
const char *cal_data;
u8 dev_type; u8 dev_type;
...@@ -91,6 +95,7 @@ struct btmrvl_private { ...@@ -91,6 +95,7 @@ struct btmrvl_private {
#define BT_CMD_HOST_SLEEP_CONFIG 0x59 #define BT_CMD_HOST_SLEEP_CONFIG 0x59
#define BT_CMD_HOST_SLEEP_ENABLE 0x5A #define BT_CMD_HOST_SLEEP_ENABLE 0x5A
#define BT_CMD_MODULE_CFG_REQ 0x5B #define BT_CMD_MODULE_CFG_REQ 0x5B
#define BT_CMD_LOAD_CONFIG_DATA 0x61
/* Sub-commands: Module Bringup/Shutdown Request/Response */ /* Sub-commands: Module Bringup/Shutdown Request/Response */
#define MODULE_BRINGUP_REQ 0xF1 #define MODULE_BRINGUP_REQ 0xF1
...@@ -116,11 +121,8 @@ struct btmrvl_private { ...@@ -116,11 +121,8 @@ struct btmrvl_private {
#define PS_SLEEP 0x01 #define PS_SLEEP 0x01
#define PS_AWAKE 0x00 #define PS_AWAKE 0x00
struct btmrvl_cmd { #define BT_CMD_DATA_SIZE 32
__le16 ocf_ogf; #define BT_CAL_DATA_SIZE 28
u8 length;
u8 data[4];
} __packed;
struct btmrvl_event { struct btmrvl_event {
u8 ec; /* event counter */ u8 ec; /* event counter */
......
...@@ -57,8 +57,7 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) ...@@ -57,8 +57,7 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb)
ocf = hci_opcode_ocf(opcode); ocf = hci_opcode_ocf(opcode);
ogf = hci_opcode_ogf(opcode); ogf = hci_opcode_ogf(opcode);
if (ocf == BT_CMD_MODULE_CFG_REQ && if (priv->btmrvl_dev.sendcmdflag) {
priv->btmrvl_dev.sendcmdflag) {
priv->btmrvl_dev.sendcmdflag = false; priv->btmrvl_dev.sendcmdflag = false;
priv->adapter->cmd_complete = true; priv->adapter->cmd_complete = true;
wake_up_interruptible(&priv->adapter->cmd_wait_q); wake_up_interruptible(&priv->adapter->cmd_wait_q);
...@@ -116,7 +115,6 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) ...@@ -116,7 +115,6 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
adapter->hs_state = HS_ACTIVATED; adapter->hs_state = HS_ACTIVATED;
if (adapter->psmode) if (adapter->psmode)
adapter->ps_state = PS_SLEEP; adapter->ps_state = PS_SLEEP;
wake_up_interruptible(&adapter->cmd_wait_q);
BT_DBG("HS ACTIVATED!"); BT_DBG("HS ACTIVATED!");
} else { } else {
BT_DBG("HS Enable failed"); BT_DBG("HS Enable failed");
...@@ -168,22 +166,24 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) ...@@ -168,22 +166,24 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
} }
EXPORT_SYMBOL_GPL(btmrvl_process_event); EXPORT_SYMBOL_GPL(btmrvl_process_event);
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 cmd_no,
const void *param, u8 len)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct btmrvl_cmd *cmd; struct hci_command_hdr *hdr;
int ret = 0;
skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); skb = bt_skb_alloc(HCI_COMMAND_HDR_SIZE + len, GFP_ATOMIC);
if (skb == NULL) { if (skb == NULL) {
BT_ERR("No free skb"); BT_ERR("No free skb");
return -ENOMEM; return -ENOMEM;
} }
cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); hdr = (struct hci_command_hdr *)skb_put(skb, HCI_COMMAND_HDR_SIZE);
cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_MODULE_CFG_REQ)); hdr->opcode = cpu_to_le16(hci_opcode_pack(OGF, cmd_no));
cmd->length = 1; hdr->plen = len;
cmd->data[0] = subcmd;
if (len)
memcpy(skb_put(skb, len), param, len);
bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
...@@ -194,19 +194,23 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) ...@@ -194,19 +194,23 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd)
priv->adapter->cmd_complete = false; priv->adapter->cmd_complete = false;
BT_DBG("Queue module cfg Command");
wake_up_interruptible(&priv->main_thread.wait_q); wake_up_interruptible(&priv->main_thread.wait_q);
if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q, if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q,
priv->adapter->cmd_complete, priv->adapter->cmd_complete,
msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) { msecs_to_jiffies(WAIT_UNTIL_CMD_RESP)))
ret = -ETIMEDOUT; return -ETIMEDOUT;
BT_ERR("module_cfg_cmd(%x): timeout: %d",
subcmd, priv->btmrvl_dev.sendcmdflag);
}
BT_DBG("module cfg Command done"); return 0;
}
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd)
{
int ret;
ret = btmrvl_send_sync_cmd(priv, BT_CMD_MODULE_CFG_REQ, &subcmd, 1);
if (ret)
BT_ERR("module_cfg_cmd(%x) failed\n", subcmd);
return ret; return ret;
} }
...@@ -214,61 +218,36 @@ EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd); ...@@ -214,61 +218,36 @@ EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd);
int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv) int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv)
{ {
struct sk_buff *skb; int ret;
struct btmrvl_cmd *cmd; u8 param[2];
skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
if (!skb) {
BT_ERR("No free skb");
return -ENOMEM;
}
cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF,
BT_CMD_HOST_SLEEP_CONFIG));
cmd->length = 2;
cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8;
cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff);
bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; param[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8;
param[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff);
skb->dev = (void *) priv->btmrvl_dev.hcidev; BT_DBG("Sending HSCFG Command, gpio=0x%x, gap=0x%x",
skb_queue_head(&priv->adapter->tx_queue, skb); param[0], param[1]);
BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x", cmd->data[0], ret = btmrvl_send_sync_cmd(priv, BT_CMD_HOST_SLEEP_CONFIG, param, 2);
cmd->data[1]); if (ret)
BT_ERR("HSCFG command failed\n");
return 0; return ret;
} }
EXPORT_SYMBOL_GPL(btmrvl_send_hscfg_cmd); EXPORT_SYMBOL_GPL(btmrvl_send_hscfg_cmd);
int btmrvl_enable_ps(struct btmrvl_private *priv) int btmrvl_enable_ps(struct btmrvl_private *priv)
{ {
struct sk_buff *skb; int ret;
struct btmrvl_cmd *cmd; u8 param;
skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
if (skb == NULL) {
BT_ERR("No free skb");
return -ENOMEM;
}
cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF,
BT_CMD_AUTO_SLEEP_MODE));
cmd->length = 1;
if (priv->btmrvl_dev.psmode) if (priv->btmrvl_dev.psmode)
cmd->data[0] = BT_PS_ENABLE; param = BT_PS_ENABLE;
else else
cmd->data[0] = BT_PS_DISABLE; param = BT_PS_DISABLE;
bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
skb->dev = (void *) priv->btmrvl_dev.hcidev; ret = btmrvl_send_sync_cmd(priv, BT_CMD_AUTO_SLEEP_MODE, &param, 1);
skb_queue_head(&priv->adapter->tx_queue, skb); if (ret)
BT_ERR("PSMODE command failed\n");
BT_DBG("Queue PSMODE Command:%d", cmd->data[0]);
return 0; return 0;
} }
...@@ -276,37 +255,11 @@ EXPORT_SYMBOL_GPL(btmrvl_enable_ps); ...@@ -276,37 +255,11 @@ EXPORT_SYMBOL_GPL(btmrvl_enable_ps);
int btmrvl_enable_hs(struct btmrvl_private *priv) int btmrvl_enable_hs(struct btmrvl_private *priv)
{ {
struct sk_buff *skb; int ret;
struct btmrvl_cmd *cmd;
int ret = 0;
skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
if (skb == NULL) {
BT_ERR("No free skb");
return -ENOMEM;
}
cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_ENABLE));
cmd->length = 0;
bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
skb->dev = (void *) priv->btmrvl_dev.hcidev;
skb_queue_head(&priv->adapter->tx_queue, skb);
BT_DBG("Queue hs enable Command");
wake_up_interruptible(&priv->main_thread.wait_q);
if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q, ret = btmrvl_send_sync_cmd(priv, BT_CMD_HOST_SLEEP_ENABLE, NULL, 0);
priv->adapter->hs_state, if (ret)
msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED))) { BT_ERR("Host sleep enable command failed\n");
ret = -ETIMEDOUT;
BT_ERR("timeout: %d, %d,%d", priv->adapter->hs_state,
priv->adapter->ps_state,
priv->adapter->wakeup_tries);
}
return ret; return ret;
} }
...@@ -479,6 +432,137 @@ static int btmrvl_open(struct hci_dev *hdev) ...@@ -479,6 +432,137 @@ static int btmrvl_open(struct hci_dev *hdev)
return 0; return 0;
} }
/*
* This function parses provided calibration data input. It should contain
* hex bytes separated by space or new line character. Here is an example.
* 00 1C 01 37 FF FF FF FF 02 04 7F 01
* CE BA 00 00 00 2D C6 C0 00 00 00 00
* 00 F0 00 00
*/
static int btmrvl_parse_cal_cfg(const u8 *src, u32 len, u8 *dst, u32 dst_size)
{
const u8 *s = src;
u8 *d = dst;
int ret;
u8 tmp[3];
tmp[2] = '\0';
while ((s - src) <= len - 2) {
if (isspace(*s)) {
s++;
continue;
}
if (isxdigit(*s)) {
if ((d - dst) >= dst_size) {
BT_ERR("calibration data file too big!!!");
return -EINVAL;
}
memcpy(tmp, s, 2);
ret = kstrtou8(tmp, 16, d++);
if (ret < 0)
return ret;
s += 2;
} else {
return -EINVAL;
}
}
if (d == dst)
return -EINVAL;
return 0;
}
static int btmrvl_load_cal_data(struct btmrvl_private *priv,
u8 *config_data)
{
int i, ret;
u8 data[BT_CMD_DATA_SIZE];
data[0] = 0x00;
data[1] = 0x00;
data[2] = 0x00;
data[3] = BT_CMD_DATA_SIZE - 4;
/* Swap cal-data bytes. Each four bytes are swapped. Considering 4
* byte SDIO header offset, mapping of input and output bytes will be
* {3, 2, 1, 0} -> {0+4, 1+4, 2+4, 3+4},
* {7, 6, 5, 4} -> {4+4, 5+4, 6+4, 7+4} */
for (i = 4; i < BT_CMD_DATA_SIZE; i++)
data[i] = config_data[(i / 4) * 8 - 1 - i];
print_hex_dump_bytes("Calibration data: ",
DUMP_PREFIX_OFFSET, data, BT_CMD_DATA_SIZE);
ret = btmrvl_send_sync_cmd(priv, BT_CMD_LOAD_CONFIG_DATA, data,
BT_CMD_DATA_SIZE);
if (ret)
BT_ERR("Failed to download caibration data\n");
return 0;
}
static int
btmrvl_process_cal_cfg(struct btmrvl_private *priv, u8 *data, u32 size)
{
u8 cal_data[BT_CAL_DATA_SIZE];
int ret;
ret = btmrvl_parse_cal_cfg(data, size, cal_data, sizeof(cal_data));
if (ret)
return ret;
ret = btmrvl_load_cal_data(priv, cal_data);
if (ret) {
BT_ERR("Fail to load calibrate data");
return ret;
}
return 0;
}
static int btmrvl_cal_data_config(struct btmrvl_private *priv)
{
const struct firmware *cfg;
int ret;
const char *cal_data = priv->btmrvl_dev.cal_data;
if (!cal_data)
return 0;
ret = request_firmware(&cfg, cal_data, priv->btmrvl_dev.dev);
if (ret < 0) {
BT_DBG("Failed to get %s file, skipping cal data download",
cal_data);
return 0;
}
ret = btmrvl_process_cal_cfg(priv, (u8 *)cfg->data, cfg->size);
release_firmware(cfg);
return ret;
}
static int btmrvl_setup(struct hci_dev *hdev)
{
struct btmrvl_private *priv = hci_get_drvdata(hdev);
btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
if (btmrvl_cal_data_config(priv))
BT_ERR("Set cal data failed");
priv->btmrvl_dev.psmode = 1;
btmrvl_enable_ps(priv);
priv->btmrvl_dev.gpio_gap = 0xffff;
btmrvl_send_hscfg_cmd(priv);
return 0;
}
/* /*
* This function handles the event generated by firmware, rx data * This function handles the event generated by firmware, rx data
* received from firmware, and tx data sent from kernel. * received from firmware, and tx data sent from kernel.
...@@ -572,8 +656,7 @@ int btmrvl_register_hdev(struct btmrvl_private *priv) ...@@ -572,8 +656,7 @@ int btmrvl_register_hdev(struct btmrvl_private *priv)
hdev->flush = btmrvl_flush; hdev->flush = btmrvl_flush;
hdev->send = btmrvl_send_frame; hdev->send = btmrvl_send_frame;
hdev->ioctl = btmrvl_ioctl; hdev->ioctl = btmrvl_ioctl;
hdev->setup = btmrvl_setup;
btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
hdev->dev_type = priv->btmrvl_dev.dev_type; hdev->dev_type = priv->btmrvl_dev.dev_type;
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
* this warranty disclaimer. * this warranty disclaimer.
**/ **/
#include <linux/firmware.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mmc/sdio_ids.h> #include <linux/mmc/sdio_ids.h>
...@@ -102,6 +101,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = { ...@@ -102,6 +101,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
.helper = "mrvl/sd8688_helper.bin", .helper = "mrvl/sd8688_helper.bin",
.firmware = "mrvl/sd8688.bin", .firmware = "mrvl/sd8688.bin",
.cal_data = NULL,
.reg = &btmrvl_reg_8688, .reg = &btmrvl_reg_8688,
.sd_blksz_fw_dl = 64, .sd_blksz_fw_dl = 64,
}; };
...@@ -109,6 +109,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { ...@@ -109,6 +109,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
.helper = NULL, .helper = NULL,
.firmware = "mrvl/sd8787_uapsta.bin", .firmware = "mrvl/sd8787_uapsta.bin",
.cal_data = NULL,
.reg = &btmrvl_reg_87xx, .reg = &btmrvl_reg_87xx,
.sd_blksz_fw_dl = 256, .sd_blksz_fw_dl = 256,
}; };
...@@ -116,6 +117,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = { ...@@ -116,6 +117,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
.helper = NULL, .helper = NULL,
.firmware = "mrvl/sd8797_uapsta.bin", .firmware = "mrvl/sd8797_uapsta.bin",
.cal_data = "mrvl/sd8797_caldata.conf",
.reg = &btmrvl_reg_87xx, .reg = &btmrvl_reg_87xx,
.sd_blksz_fw_dl = 256, .sd_blksz_fw_dl = 256,
}; };
...@@ -123,6 +125,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { ...@@ -123,6 +125,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
.helper = NULL, .helper = NULL,
.firmware = "mrvl/sd8897_uapsta.bin", .firmware = "mrvl/sd8897_uapsta.bin",
.cal_data = NULL,
.reg = &btmrvl_reg_88xx, .reg = &btmrvl_reg_88xx,
.sd_blksz_fw_dl = 256, .sd_blksz_fw_dl = 256,
}; };
...@@ -1006,6 +1009,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func, ...@@ -1006,6 +1009,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
struct btmrvl_sdio_device *data = (void *) id->driver_data; struct btmrvl_sdio_device *data = (void *) id->driver_data;
card->helper = data->helper; card->helper = data->helper;
card->firmware = data->firmware; card->firmware = data->firmware;
card->cal_data = data->cal_data;
card->reg = data->reg; card->reg = data->reg;
card->sd_blksz_fw_dl = data->sd_blksz_fw_dl; card->sd_blksz_fw_dl = data->sd_blksz_fw_dl;
} }
...@@ -1034,6 +1038,8 @@ static int btmrvl_sdio_probe(struct sdio_func *func, ...@@ -1034,6 +1038,8 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
} }
card->priv = priv; card->priv = priv;
priv->btmrvl_dev.dev = &card->func->dev;
priv->btmrvl_dev.cal_data = card->cal_data;
/* Initialize the interface specific function pointers */ /* Initialize the interface specific function pointers */
priv->hw_host_to_card = btmrvl_sdio_host_to_card; priv->hw_host_to_card = btmrvl_sdio_host_to_card;
...@@ -1046,12 +1052,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func, ...@@ -1046,12 +1052,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
goto disable_host_int; goto disable_host_int;
} }
priv->btmrvl_dev.psmode = 1;
btmrvl_enable_ps(priv);
priv->btmrvl_dev.gpio_gap = 0xffff;
btmrvl_send_hscfg_cmd(priv);
return 0; return 0;
disable_host_int: disable_host_int:
...@@ -1222,4 +1222,5 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin"); ...@@ -1222,4 +1222,5 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
MODULE_FIRMWARE("mrvl/sd8688.bin"); MODULE_FIRMWARE("mrvl/sd8688.bin");
MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
MODULE_FIRMWARE("mrvl/sd8797_caldata.conf");
MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
...@@ -85,6 +85,7 @@ struct btmrvl_sdio_card { ...@@ -85,6 +85,7 @@ struct btmrvl_sdio_card {
u32 ioport; u32 ioport;
const char *helper; const char *helper;
const char *firmware; const char *firmware;
const char *cal_data;
const struct btmrvl_sdio_card_reg *reg; const struct btmrvl_sdio_card_reg *reg;
u16 sd_blksz_fw_dl; u16 sd_blksz_fw_dl;
u8 rx_unit; u8 rx_unit;
...@@ -94,6 +95,7 @@ struct btmrvl_sdio_card { ...@@ -94,6 +95,7 @@ struct btmrvl_sdio_card {
struct btmrvl_sdio_device { struct btmrvl_sdio_device {
const char *helper; const char *helper;
const char *firmware; const char *firmware;
const char *cal_data;
const struct btmrvl_sdio_card_reg *reg; const struct btmrvl_sdio_card_reg *reg;
u16 sd_blksz_fw_dl; u16 sd_blksz_fw_dl;
}; };
......
...@@ -102,6 +102,7 @@ static struct usb_device_id btusb_table[] = { ...@@ -102,6 +102,7 @@ static struct usb_device_id btusb_table[] = {
/* Broadcom BCM20702A0 */ /* Broadcom BCM20702A0 */
{ USB_DEVICE(0x0b05, 0x17b5) }, { USB_DEVICE(0x0b05, 0x17b5) },
{ USB_DEVICE(0x0b05, 0x17cb) },
{ USB_DEVICE(0x04ca, 0x2003) }, { USB_DEVICE(0x04ca, 0x2003) },
{ USB_DEVICE(0x0489, 0xe042) }, { USB_DEVICE(0x0489, 0xe042) },
{ USB_DEVICE(0x413c, 0x8197) }, { USB_DEVICE(0x413c, 0x8197) },
...@@ -112,6 +113,9 @@ static struct usb_device_id btusb_table[] = { ...@@ -112,6 +113,9 @@ static struct usb_device_id btusb_table[] = {
/*Broadcom devices with vendor specific id */ /*Broadcom devices with vendor specific id */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) }, { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
/* Belkin F8065bf - Broadcom based */
{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
...@@ -148,6 +152,7 @@ static struct usb_device_id blacklist_table[] = { ...@@ -148,6 +152,7 @@ static struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <asm/unaligned.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -39,17 +40,17 @@ ...@@ -39,17 +40,17 @@
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#define VERSION "1.3" #define VERSION "1.4"
static bool amp; static bool amp;
struct vhci_data { struct vhci_data {
struct hci_dev *hdev; struct hci_dev *hdev;
unsigned long flags;
wait_queue_head_t read_wait; wait_queue_head_t read_wait;
struct sk_buff_head readq; struct sk_buff_head readq;
struct delayed_work open_timeout;
}; };
static int vhci_open_dev(struct hci_dev *hdev) static int vhci_open_dev(struct hci_dev *hdev)
...@@ -99,16 +100,62 @@ static int vhci_send_frame(struct sk_buff *skb) ...@@ -99,16 +100,62 @@ static int vhci_send_frame(struct sk_buff *skb)
skb_queue_tail(&data->readq, skb); skb_queue_tail(&data->readq, skb);
wake_up_interruptible(&data->read_wait); wake_up_interruptible(&data->read_wait);
return 0;
}
static int vhci_create_device(struct vhci_data *data, __u8 dev_type)
{
struct hci_dev *hdev;
struct sk_buff *skb;
skb = bt_skb_alloc(4, GFP_KERNEL);
if (!skb)
return -ENOMEM;
hdev = hci_alloc_dev();
if (!hdev) {
kfree_skb(skb);
return -ENOMEM;
}
data->hdev = hdev;
hdev->bus = HCI_VIRTUAL;
hdev->dev_type = dev_type;
hci_set_drvdata(hdev, data);
hdev->open = vhci_open_dev;
hdev->close = vhci_close_dev;
hdev->flush = vhci_flush;
hdev->send = vhci_send_frame;
if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device");
hci_free_dev(hdev);
data->hdev = NULL;
kfree_skb(skb);
return -EBUSY;
}
bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
*skb_put(skb, 1) = 0xff;
*skb_put(skb, 1) = dev_type;
put_unaligned_le16(hdev->id, skb_put(skb, 2));
skb_queue_tail(&data->readq, skb);
wake_up_interruptible(&data->read_wait);
return 0; return 0;
} }
static inline ssize_t vhci_get_user(struct vhci_data *data, static inline ssize_t vhci_get_user(struct vhci_data *data,
const char __user *buf, size_t count) const char __user *buf, size_t count)
{ {
struct sk_buff *skb; struct sk_buff *skb;
__u8 pkt_type, dev_type;
int ret;
if (count > HCI_MAX_FRAME_SIZE) if (count < 2 || count > HCI_MAX_FRAME_SIZE)
return -EINVAL; return -EINVAL;
skb = bt_skb_alloc(count, GFP_KERNEL); skb = bt_skb_alloc(count, GFP_KERNEL);
...@@ -120,27 +167,70 @@ static inline ssize_t vhci_get_user(struct vhci_data *data, ...@@ -120,27 +167,70 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
return -EFAULT; return -EFAULT;
} }
skb->dev = (void *) data->hdev; pkt_type = *((__u8 *) skb->data);
bt_cb(skb)->pkt_type = *((__u8 *) skb->data);
skb_pull(skb, 1); skb_pull(skb, 1);
hci_recv_frame(skb); switch (pkt_type) {
case HCI_EVENT_PKT:
case HCI_ACLDATA_PKT:
case HCI_SCODATA_PKT:
if (!data->hdev) {
kfree_skb(skb);
return -ENODEV;
}
skb->dev = (void *) data->hdev;
bt_cb(skb)->pkt_type = pkt_type;
ret = hci_recv_frame(skb);
break;
case HCI_VENDOR_PKT:
if (data->hdev) {
kfree_skb(skb);
return -EBADFD;
}
return count; cancel_delayed_work_sync(&data->open_timeout);
dev_type = *((__u8 *) skb->data);
skb_pull(skb, 1);
if (skb->len > 0) {
kfree_skb(skb);
return -EINVAL;
}
kfree_skb(skb);
if (dev_type != HCI_BREDR && dev_type != HCI_AMP)
return -EINVAL;
ret = vhci_create_device(data, dev_type);
break;
default:
kfree_skb(skb);
return -EINVAL;
}
return (ret < 0) ? ret : count;
} }
static inline ssize_t vhci_put_user(struct vhci_data *data, static inline ssize_t vhci_put_user(struct vhci_data *data,
struct sk_buff *skb, char __user *buf, int count) struct sk_buff *skb,
char __user *buf, int count)
{ {
char __user *ptr = buf; char __user *ptr = buf;
int len, total = 0; int len;
len = min_t(unsigned int, skb->len, count); len = min_t(unsigned int, skb->len, count);
if (copy_to_user(ptr, skb->data, len)) if (copy_to_user(ptr, skb->data, len))
return -EFAULT; return -EFAULT;
total += len; if (!data->hdev)
return len;
data->hdev->stat.byte_tx += len; data->hdev->stat.byte_tx += len;
...@@ -148,21 +238,19 @@ static inline ssize_t vhci_put_user(struct vhci_data *data, ...@@ -148,21 +238,19 @@ static inline ssize_t vhci_put_user(struct vhci_data *data,
case HCI_COMMAND_PKT: case HCI_COMMAND_PKT:
data->hdev->stat.cmd_tx++; data->hdev->stat.cmd_tx++;
break; break;
case HCI_ACLDATA_PKT: case HCI_ACLDATA_PKT:
data->hdev->stat.acl_tx++; data->hdev->stat.acl_tx++;
break; break;
case HCI_SCODATA_PKT: case HCI_SCODATA_PKT:
data->hdev->stat.sco_tx++; data->hdev->stat.sco_tx++;
break; break;
} }
return total; return len;
} }
static ssize_t vhci_read(struct file *file, static ssize_t vhci_read(struct file *file,
char __user *buf, size_t count, loff_t *pos) char __user *buf, size_t count, loff_t *pos)
{ {
struct vhci_data *data = file->private_data; struct vhci_data *data = file->private_data;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -185,7 +273,7 @@ static ssize_t vhci_read(struct file *file, ...@@ -185,7 +273,7 @@ static ssize_t vhci_read(struct file *file,
} }
ret = wait_event_interruptible(data->read_wait, ret = wait_event_interruptible(data->read_wait,
!skb_queue_empty(&data->readq)); !skb_queue_empty(&data->readq));
if (ret < 0) if (ret < 0)
break; break;
} }
...@@ -194,7 +282,7 @@ static ssize_t vhci_read(struct file *file, ...@@ -194,7 +282,7 @@ static ssize_t vhci_read(struct file *file,
} }
static ssize_t vhci_write(struct file *file, static ssize_t vhci_write(struct file *file,
const char __user *buf, size_t count, loff_t *pos) const char __user *buf, size_t count, loff_t *pos)
{ {
struct vhci_data *data = file->private_data; struct vhci_data *data = file->private_data;
...@@ -213,10 +301,17 @@ static unsigned int vhci_poll(struct file *file, poll_table *wait) ...@@ -213,10 +301,17 @@ static unsigned int vhci_poll(struct file *file, poll_table *wait)
return POLLOUT | POLLWRNORM; return POLLOUT | POLLWRNORM;
} }
static void vhci_open_timeout(struct work_struct *work)
{
struct vhci_data *data = container_of(work, struct vhci_data,
open_timeout.work);
vhci_create_device(data, amp ? HCI_AMP : HCI_BREDR);
}
static int vhci_open(struct inode *inode, struct file *file) static int vhci_open(struct inode *inode, struct file *file)
{ {
struct vhci_data *data; struct vhci_data *data;
struct hci_dev *hdev;
data = kzalloc(sizeof(struct vhci_data), GFP_KERNEL); data = kzalloc(sizeof(struct vhci_data), GFP_KERNEL);
if (!data) if (!data)
...@@ -225,35 +320,13 @@ static int vhci_open(struct inode *inode, struct file *file) ...@@ -225,35 +320,13 @@ static int vhci_open(struct inode *inode, struct file *file)
skb_queue_head_init(&data->readq); skb_queue_head_init(&data->readq);
init_waitqueue_head(&data->read_wait); init_waitqueue_head(&data->read_wait);
hdev = hci_alloc_dev(); INIT_DELAYED_WORK(&data->open_timeout, vhci_open_timeout);
if (!hdev) {
kfree(data);
return -ENOMEM;
}
data->hdev = hdev;
hdev->bus = HCI_VIRTUAL;
hci_set_drvdata(hdev, data);
if (amp)
hdev->dev_type = HCI_AMP;
hdev->open = vhci_open_dev;
hdev->close = vhci_close_dev;
hdev->flush = vhci_flush;
hdev->send = vhci_send_frame;
if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device");
kfree(data);
hci_free_dev(hdev);
return -EBUSY;
}
file->private_data = data; file->private_data = data;
nonseekable_open(inode, file); nonseekable_open(inode, file);
schedule_delayed_work(&data->open_timeout, msecs_to_jiffies(1000));
return 0; return 0;
} }
...@@ -262,8 +335,12 @@ static int vhci_release(struct inode *inode, struct file *file) ...@@ -262,8 +335,12 @@ static int vhci_release(struct inode *inode, struct file *file)
struct vhci_data *data = file->private_data; struct vhci_data *data = file->private_data;
struct hci_dev *hdev = data->hdev; struct hci_dev *hdev = data->hdev;
hci_unregister_dev(hdev); cancel_delayed_work_sync(&data->open_timeout);
hci_free_dev(hdev);
if (hdev) {
hci_unregister_dev(hdev);
hci_free_dev(hdev);
}
file->private_data = NULL; file->private_data = NULL;
kfree(data); kfree(data);
...@@ -309,3 +386,4 @@ MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); ...@@ -309,3 +386,4 @@ MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION); MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("devname:vhci");
...@@ -197,8 +197,8 @@ static inline bool bdaddr_type_is_le(__u8 type) ...@@ -197,8 +197,8 @@ static inline bool bdaddr_type_is_le(__u8 type)
return false; return false;
} }
#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0} }) #define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff} }) #define BDADDR_NONE (&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}})
/* Copy, swap, convert BD Address */ /* Copy, swap, convert BD Address */
static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2) static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2)
...@@ -249,6 +249,7 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -249,6 +249,7 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
uint bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait); uint bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait);
int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo); int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
int bt_sock_wait_ready(struct sock *sk, unsigned long flags);
void bt_accept_enqueue(struct sock *parent, struct sock *sk); void bt_accept_enqueue(struct sock *parent, struct sock *sk);
void bt_accept_unlink(struct sock *sk); void bt_accept_unlink(struct sock *sk);
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#define HCI_MAX_AMP_ASSOC_SIZE 672 #define HCI_MAX_AMP_ASSOC_SIZE 672
#define HCI_MAX_CSB_DATA_SIZE 252
/* HCI dev events */ /* HCI dev events */
#define HCI_DEV_REG 1 #define HCI_DEV_REG 1
#define HCI_DEV_UNREG 2 #define HCI_DEV_UNREG 2
...@@ -104,11 +106,13 @@ enum { ...@@ -104,11 +106,13 @@ enum {
enum { enum {
HCI_SETUP, HCI_SETUP,
HCI_AUTO_OFF, HCI_AUTO_OFF,
HCI_RFKILLED,
HCI_MGMT, HCI_MGMT,
HCI_PAIRABLE, HCI_PAIRABLE,
HCI_SERVICE_CACHE, HCI_SERVICE_CACHE,
HCI_DEBUG_KEYS, HCI_DEBUG_KEYS,
HCI_UNREGISTER, HCI_UNREGISTER,
HCI_USER_CHANNEL,
HCI_LE_SCAN, HCI_LE_SCAN,
HCI_SSP_ENABLED, HCI_SSP_ENABLED,
...@@ -120,6 +124,7 @@ enum { ...@@ -120,6 +124,7 @@ enum {
HCI_LINK_SECURITY, HCI_LINK_SECURITY,
HCI_PERIODIC_INQ, HCI_PERIODIC_INQ,
HCI_FAST_CONNECTABLE, HCI_FAST_CONNECTABLE,
HCI_BREDR_ENABLED,
}; };
/* A mask for the flags that are supposed to remain when a reset happens /* A mask for the flags that are supposed to remain when a reset happens
...@@ -623,6 +628,24 @@ struct hci_rp_logical_link_cancel { ...@@ -623,6 +628,24 @@ struct hci_rp_logical_link_cancel {
__u8 flow_spec_id; __u8 flow_spec_id;
} __packed; } __packed;
#define HCI_OP_SET_CSB 0x0441
struct hci_cp_set_csb {
__u8 enable;
__u8 lt_addr;
__u8 lpo_allowed;
__le16 packet_type;
__le16 interval_min;
__le16 interval_max;
__le16 csb_sv_tout;
} __packed;
struct hci_rp_set_csb {
__u8 status;
__u8 lt_addr;
__le16 interval;
} __packed;
#define HCI_OP_START_SYNC_TRAIN 0x0443
#define HCI_OP_SNIFF_MODE 0x0803 #define HCI_OP_SNIFF_MODE 0x0803
struct hci_cp_sniff_mode { struct hci_cp_sniff_mode {
__le16 handle; __le16 handle;
...@@ -693,9 +716,6 @@ struct hci_cp_sniff_subrate { ...@@ -693,9 +716,6 @@ struct hci_cp_sniff_subrate {
} __packed; } __packed;
#define HCI_OP_SET_EVENT_MASK 0x0c01 #define HCI_OP_SET_EVENT_MASK 0x0c01
struct hci_cp_set_event_mask {
__u8 mask[8];
} __packed;
#define HCI_OP_RESET 0x0c03 #define HCI_OP_RESET 0x0c03
...@@ -825,6 +845,8 @@ struct hci_rp_read_inq_rsp_tx_power { ...@@ -825,6 +845,8 @@ struct hci_rp_read_inq_rsp_tx_power {
__s8 tx_power; __s8 tx_power;
} __packed; } __packed;
#define HCI_OP_SET_EVENT_MASK_PAGE_2 0x0c63
#define HCI_OP_READ_FLOW_CONTROL_MODE 0x0c66 #define HCI_OP_READ_FLOW_CONTROL_MODE 0x0c66
struct hci_rp_read_flow_control_mode { struct hci_rp_read_flow_control_mode {
__u8 status; __u8 status;
...@@ -837,6 +859,50 @@ struct hci_cp_write_le_host_supported { ...@@ -837,6 +859,50 @@ struct hci_cp_write_le_host_supported {
__u8 simul; __u8 simul;
} __packed; } __packed;
#define HCI_OP_SET_RESERVED_LT_ADDR 0x0c74
struct hci_cp_set_reserved_lt_addr {
__u8 lt_addr;
} __packed;
struct hci_rp_set_reserved_lt_addr {
__u8 status;
__u8 lt_addr;
} __packed;
#define HCI_OP_DELETE_RESERVED_LT_ADDR 0x0c75
struct hci_cp_delete_reserved_lt_addr {
__u8 lt_addr;
} __packed;
struct hci_rp_delete_reserved_lt_addr {
__u8 status;
__u8 lt_addr;
} __packed;
#define HCI_OP_SET_CSB_DATA 0x0c76
struct hci_cp_set_csb_data {
__u8 lt_addr;
__u8 fragment;
__u8 data_length;
__u8 data[HCI_MAX_CSB_DATA_SIZE];
} __packed;
struct hci_rp_set_csb_data {
__u8 status;
__u8 lt_addr;
} __packed;
#define HCI_OP_READ_SYNC_TRAIN_PARAMS 0x0c77
#define HCI_OP_WRITE_SYNC_TRAIN_PARAMS 0x0c78
struct hci_cp_write_sync_train_params {
__le16 interval_min;
__le16 interval_max;
__le32 sync_train_tout;
__u8 service_data;
} __packed;
struct hci_rp_write_sync_train_params {
__u8 status;
__le16 sync_train_int;
} __packed;
#define HCI_OP_READ_LOCAL_VERSION 0x1001 #define HCI_OP_READ_LOCAL_VERSION 0x1001
struct hci_rp_read_local_version { struct hci_rp_read_local_version {
__u8 status; __u8 status;
...@@ -974,6 +1040,8 @@ struct hci_rp_le_read_local_features { ...@@ -974,6 +1040,8 @@ struct hci_rp_le_read_local_features {
__u8 features[8]; __u8 features[8];
} __packed; } __packed;
#define HCI_OP_LE_SET_RANDOM_ADDR 0x2005
#define HCI_OP_LE_READ_ADV_TX_POWER 0x2007 #define HCI_OP_LE_READ_ADV_TX_POWER 0x2007
struct hci_rp_le_read_adv_tx_power { struct hci_rp_le_read_adv_tx_power {
__u8 status; __u8 status;
...@@ -1437,6 +1505,13 @@ struct hci_ev_num_comp_blocks { ...@@ -1437,6 +1505,13 @@ struct hci_ev_num_comp_blocks {
struct hci_comp_blocks_info handles[0]; struct hci_comp_blocks_info handles[0];
} __packed; } __packed;
#define HCI_EV_SYNC_TRAIN_COMPLETE 0x4F
struct hci_ev_sync_train_complete {
__u8 status;
} __packed;
#define HCI_EV_SLAVE_PAGE_RESP_TIMEOUT 0x54
/* Low energy meta events */ /* Low energy meta events */
#define LE_CONN_ROLE_MASTER 0x00 #define LE_CONN_ROLE_MASTER 0x00
...@@ -1570,6 +1645,7 @@ struct sockaddr_hci { ...@@ -1570,6 +1645,7 @@ struct sockaddr_hci {
#define HCI_DEV_NONE 0xffff #define HCI_DEV_NONE 0xffff
#define HCI_CHANNEL_RAW 0 #define HCI_CHANNEL_RAW 0
#define HCI_CHANNEL_USER 1
#define HCI_CHANNEL_MONITOR 2 #define HCI_CHANNEL_MONITOR 2
#define HCI_CHANNEL_CONTROL 3 #define HCI_CHANNEL_CONTROL 3
......
...@@ -140,6 +140,7 @@ struct hci_dev { ...@@ -140,6 +140,7 @@ struct hci_dev {
__u8 bus; __u8 bus;
__u8 dev_type; __u8 dev_type;
bdaddr_t bdaddr; bdaddr_t bdaddr;
bdaddr_t static_addr;
__u8 dev_name[HCI_MAX_NAME_LENGTH]; __u8 dev_name[HCI_MAX_NAME_LENGTH];
__u8 short_name[HCI_MAX_SHORT_NAME_LENGTH]; __u8 short_name[HCI_MAX_SHORT_NAME_LENGTH];
__u8 eir[HCI_MAX_EIR_LENGTH]; __u8 eir[HCI_MAX_EIR_LENGTH];
...@@ -1168,7 +1169,6 @@ int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, ...@@ -1168,7 +1169,6 @@ int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
u8 *randomizer, u8 status); u8 *randomizer, u8 status);
int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, int 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);
......
...@@ -564,6 +564,7 @@ struct l2cap_conn { ...@@ -564,6 +564,7 @@ struct l2cap_conn {
__u32 feat_mask; __u32 feat_mask;
__u8 fixed_chan_mask; __u8 fixed_chan_mask;
bool hs_enabled;
__u8 info_state; __u8 info_state;
__u8 info_ident; __u8 info_ident;
......
...@@ -93,6 +93,7 @@ struct mgmt_rp_read_index_list { ...@@ -93,6 +93,7 @@ struct mgmt_rp_read_index_list {
#define MGMT_SETTING_BREDR 0x00000080 #define MGMT_SETTING_BREDR 0x00000080
#define MGMT_SETTING_HS 0x00000100 #define MGMT_SETTING_HS 0x00000100
#define MGMT_SETTING_LE 0x00000200 #define MGMT_SETTING_LE 0x00000200
#define MGMT_SETTING_ADVERTISING 0x00000400
#define MGMT_OP_READ_INFO 0x0004 #define MGMT_OP_READ_INFO 0x0004
#define MGMT_READ_INFO_SIZE 0 #define MGMT_READ_INFO_SIZE 0
...@@ -351,6 +352,16 @@ struct mgmt_cp_set_device_id { ...@@ -351,6 +352,16 @@ struct mgmt_cp_set_device_id {
} __packed; } __packed;
#define MGMT_SET_DEVICE_ID_SIZE 8 #define MGMT_SET_DEVICE_ID_SIZE 8
#define MGMT_OP_SET_ADVERTISING 0x0029
#define MGMT_OP_SET_BREDR 0x002A
#define MGMT_OP_SET_STATIC_ADDRESS 0x002B
struct mgmt_cp_set_static_address {
bdaddr_t bdaddr;
} __packed;
#define MGMT_SET_STATIC_ADDRESS_SIZE 6
#define MGMT_EV_CMD_COMPLETE 0x0001 #define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete { struct mgmt_ev_cmd_complete {
__le16 opcode; __le16 opcode;
......
...@@ -11,3 +11,5 @@ obj-$(CONFIG_BT_HIDP) += hidp/ ...@@ -11,3 +11,5 @@ obj-$(CONFIG_BT_HIDP) += hidp/
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
a2mp.o amp.o a2mp.o amp.o
subdir-ccflags-y += -D__CHECK_ENDIAN__
...@@ -490,6 +490,7 @@ int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ...@@ -490,6 +490,7 @@ int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
} }
EXPORT_SYMBOL(bt_sock_ioctl); EXPORT_SYMBOL(bt_sock_ioctl);
/* This function expects the sk lock to be held when called */
int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo) int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
...@@ -525,6 +526,46 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo) ...@@ -525,6 +526,46 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
} }
EXPORT_SYMBOL(bt_sock_wait_state); EXPORT_SYMBOL(bt_sock_wait_state);
/* This function expects the sk lock to be held when called */
int bt_sock_wait_ready(struct sock *sk, unsigned long flags)
{
DECLARE_WAITQUEUE(wait, current);
unsigned long timeo;
int err = 0;
BT_DBG("sk %p", sk);
timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
add_wait_queue(sk_sleep(sk), &wait);
set_current_state(TASK_INTERRUPTIBLE);
while (test_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags)) {
if (!timeo) {
err = -EAGAIN;
break;
}
if (signal_pending(current)) {
err = sock_intr_errno(timeo);
break;
}
release_sock(sk);
timeo = schedule_timeout(timeo);
lock_sock(sk);
set_current_state(TASK_INTERRUPTIBLE);
err = sock_error(sk);
if (err)
break;
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
return err;
}
EXPORT_SYMBOL(bt_sock_wait_ready);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
struct bt_seq_state { struct bt_seq_state {
struct bt_sock_list *l; struct bt_sock_list *l;
......
...@@ -518,6 +518,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) ...@@ -518,6 +518,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
list_for_each_entry(d, &hci_dev_list, list) { list_for_each_entry(d, &hci_dev_list, list) {
if (!test_bit(HCI_UP, &d->flags) || if (!test_bit(HCI_UP, &d->flags) ||
test_bit(HCI_RAW, &d->flags) || test_bit(HCI_RAW, &d->flags) ||
test_bit(HCI_USER_CHANNEL, &d->dev_flags) ||
d->dev_type != HCI_BREDR) d->dev_type != HCI_BREDR)
continue; continue;
...@@ -580,6 +581,9 @@ static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, ...@@ -580,6 +581,9 @@ static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
{ {
struct hci_conn *acl; struct hci_conn *acl;
if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
return ERR_PTR(-ENOTSUPP);
acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
if (!acl) { if (!acl) {
acl = hci_conn_add(hdev, ACL_LINK, dst); acl = hci_conn_add(hdev, ACL_LINK, dst);
......
This diff is collapsed.
...@@ -297,6 +297,11 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -297,6 +297,11 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
goto done; goto done;
} }
/* We need to ensure that we set this back on if someone changed
* the scan mode through a raw HCI socket.
*/
set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags); old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags);
old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags); old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags);
...@@ -994,20 +999,20 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev, ...@@ -994,20 +999,20 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
return; return;
if (!status) { if (!status) {
if (sent->le) if (sent->le) {
hdev->features[1][0] |= LMP_HOST_LE; hdev->features[1][0] |= LMP_HOST_LE;
else set_bit(HCI_LE_ENABLED, &hdev->dev_flags);
} else {
hdev->features[1][0] &= ~LMP_HOST_LE; hdev->features[1][0] &= ~LMP_HOST_LE;
clear_bit(HCI_LE_ENABLED, &hdev->dev_flags);
clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
}
if (sent->simul) if (sent->simul)
hdev->features[1][0] |= LMP_HOST_LE_BREDR; hdev->features[1][0] |= LMP_HOST_LE_BREDR;
else else
hdev->features[1][0] &= ~LMP_HOST_LE_BREDR; hdev->features[1][0] &= ~LMP_HOST_LE_BREDR;
} }
if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
!test_bit(HCI_INIT, &hdev->flags))
mgmt_le_enable_complete(hdev, sent->le, status);
} }
static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev, static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
...@@ -3557,7 +3562,11 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -3557,7 +3562,11 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
cp.handle = cpu_to_le16(conn->handle); cp.handle = cpu_to_le16(conn->handle);
if (ltk->authenticated) if (ltk->authenticated)
conn->sec_level = BT_SECURITY_HIGH; conn->pending_sec_level = BT_SECURITY_HIGH;
else
conn->pending_sec_level = BT_SECURITY_MEDIUM;
conn->enc_key_size = ltk->enc_size;
hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp); hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
......
...@@ -66,6 +66,46 @@ static struct bt_sock_list hci_sk_list = { ...@@ -66,6 +66,46 @@ static struct bt_sock_list hci_sk_list = {
.lock = __RW_LOCK_UNLOCKED(hci_sk_list.lock) .lock = __RW_LOCK_UNLOCKED(hci_sk_list.lock)
}; };
static bool is_filtered_packet(struct sock *sk, struct sk_buff *skb)
{
struct hci_filter *flt;
int flt_type, flt_event;
/* Apply filter */
flt = &hci_pi(sk)->filter;
if (bt_cb(skb)->pkt_type == HCI_VENDOR_PKT)
flt_type = 0;
else
flt_type = bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS;
if (!test_bit(flt_type, &flt->type_mask))
return true;
/* Extra filter for event packets only */
if (bt_cb(skb)->pkt_type != HCI_EVENT_PKT)
return false;
flt_event = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
if (!hci_test_bit(flt_event, &flt->event_mask))
return true;
/* Check filter only when opcode is set */
if (!flt->opcode)
return false;
if (flt_event == HCI_EV_CMD_COMPLETE &&
flt->opcode != get_unaligned((__le16 *)(skb->data + 3)))
return true;
if (flt_event == HCI_EV_CMD_STATUS &&
flt->opcode != get_unaligned((__le16 *)(skb->data + 4)))
return true;
return false;
}
/* Send frame to RAW socket */ /* Send frame to RAW socket */
void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
{ {
...@@ -77,7 +117,6 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -77,7 +117,6 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
read_lock(&hci_sk_list.lock); read_lock(&hci_sk_list.lock);
sk_for_each(sk, &hci_sk_list.head) { sk_for_each(sk, &hci_sk_list.head) {
struct hci_filter *flt;
struct sk_buff *nskb; struct sk_buff *nskb;
if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev) if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev)
...@@ -87,31 +126,19 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -87,31 +126,19 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
if (skb->sk == sk) if (skb->sk == sk)
continue; continue;
if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) if (hci_pi(sk)->channel == HCI_CHANNEL_RAW) {
continue; if (is_filtered_packet(sk, skb))
/* Apply filter */
flt = &hci_pi(sk)->filter;
if (!test_bit((bt_cb(skb)->pkt_type == HCI_VENDOR_PKT) ?
0 : (bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS),
&flt->type_mask))
continue;
if (bt_cb(skb)->pkt_type == HCI_EVENT_PKT) {
int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
if (!hci_test_bit(evt, &flt->event_mask))
continue; continue;
} else if (hci_pi(sk)->channel == HCI_CHANNEL_USER) {
if (flt->opcode && if (!bt_cb(skb)->incoming)
((evt == HCI_EV_CMD_COMPLETE && continue;
flt->opcode != if (bt_cb(skb)->pkt_type != HCI_EVENT_PKT &&
get_unaligned((__le16 *)(skb->data + 3))) || bt_cb(skb)->pkt_type != HCI_ACLDATA_PKT &&
(evt == HCI_EV_CMD_STATUS && bt_cb(skb)->pkt_type != HCI_SCODATA_PKT)
flt->opcode !=
get_unaligned((__le16 *)(skb->data + 4)))))
continue; continue;
} else {
/* Don't send frame to other channel types */
continue;
} }
if (!skb_copy) { if (!skb_copy) {
...@@ -426,6 +453,12 @@ static int hci_sock_release(struct socket *sock) ...@@ -426,6 +453,12 @@ static int hci_sock_release(struct socket *sock)
bt_sock_unlink(&hci_sk_list, sk); bt_sock_unlink(&hci_sk_list, sk);
if (hdev) { if (hdev) {
if (hci_pi(sk)->channel == HCI_CHANNEL_USER) {
mgmt_index_added(hdev);
clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags);
hci_dev_close(hdev->id);
}
atomic_dec(&hdev->promisc); atomic_dec(&hdev->promisc);
hci_dev_put(hdev); hci_dev_put(hdev);
} }
...@@ -482,6 +515,9 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, ...@@ -482,6 +515,9 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd,
if (!hdev) if (!hdev)
return -EBADFD; return -EBADFD;
if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags))
return -EBUSY;
switch (cmd) { switch (cmd) {
case HCISETRAW: case HCISETRAW:
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
...@@ -512,23 +548,32 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, ...@@ -512,23 +548,32 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd,
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
return hci_sock_blacklist_del(hdev, (void __user *) arg); return hci_sock_blacklist_del(hdev, (void __user *) arg);
default:
if (hdev->ioctl)
return hdev->ioctl(hdev, cmd, arg);
return -EINVAL;
} }
if (hdev->ioctl)
return hdev->ioctl(hdev, cmd, arg);
return -EINVAL;
} }
static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, static int hci_sock_ioctl(struct socket *sock, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
struct sock *sk = sock->sk;
void __user *argp = (void __user *) arg; void __user *argp = (void __user *) arg;
struct sock *sk = sock->sk;
int err; int err;
BT_DBG("cmd %x arg %lx", cmd, arg); BT_DBG("cmd %x arg %lx", cmd, arg);
lock_sock(sk);
if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) {
err = -EBADFD;
goto done;
}
release_sock(sk);
switch (cmd) { switch (cmd) {
case HCIGETDEVLIST: case HCIGETDEVLIST:
return hci_get_dev_list(argp); return hci_get_dev_list(argp);
...@@ -573,13 +618,15 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, ...@@ -573,13 +618,15 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd,
case HCIINQUIRY: case HCIINQUIRY:
return hci_inquiry(argp); return hci_inquiry(argp);
default:
lock_sock(sk);
err = hci_sock_bound_ioctl(sk, cmd, arg);
release_sock(sk);
return err;
} }
lock_sock(sk);
err = hci_sock_bound_ioctl(sk, cmd, arg);
done:
release_sock(sk);
return err;
} }
static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
...@@ -629,6 +676,56 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, ...@@ -629,6 +676,56 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
hci_pi(sk)->hdev = hdev; hci_pi(sk)->hdev = hdev;
break; break;
case HCI_CHANNEL_USER:
if (hci_pi(sk)->hdev) {
err = -EALREADY;
goto done;
}
if (haddr.hci_dev == HCI_DEV_NONE) {
err = -EINVAL;
goto done;
}
if (!capable(CAP_NET_ADMIN)) {
err = -EPERM;
goto done;
}
hdev = hci_dev_get(haddr.hci_dev);
if (!hdev) {
err = -ENODEV;
goto done;
}
if (test_bit(HCI_UP, &hdev->flags) ||
test_bit(HCI_INIT, &hdev->flags) ||
test_bit(HCI_SETUP, &hdev->dev_flags)) {
err = -EBUSY;
hci_dev_put(hdev);
goto done;
}
if (test_and_set_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
err = -EUSERS;
hci_dev_put(hdev);
goto done;
}
mgmt_index_removed(hdev);
err = hci_dev_open(hdev->id);
if (err) {
clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags);
hci_dev_put(hdev);
goto done;
}
atomic_inc(&hdev->promisc);
hci_pi(sk)->hdev = hdev;
break;
case HCI_CHANNEL_CONTROL: case HCI_CHANNEL_CONTROL:
if (haddr.hci_dev != HCI_DEV_NONE) { if (haddr.hci_dev != HCI_DEV_NONE) {
err = -EINVAL; err = -EINVAL;
...@@ -677,22 +774,30 @@ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, ...@@ -677,22 +774,30 @@ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr,
{ {
struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr; struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct hci_dev *hdev = hci_pi(sk)->hdev; struct hci_dev *hdev;
int err = 0;
BT_DBG("sock %p sk %p", sock, sk); BT_DBG("sock %p sk %p", sock, sk);
if (!hdev) if (peer)
return -EBADFD; return -EOPNOTSUPP;
lock_sock(sk); lock_sock(sk);
hdev = hci_pi(sk)->hdev;
if (!hdev) {
err = -EBADFD;
goto done;
}
*addr_len = sizeof(*haddr); *addr_len = sizeof(*haddr);
haddr->hci_family = AF_BLUETOOTH; haddr->hci_family = AF_BLUETOOTH;
haddr->hci_dev = hdev->id; haddr->hci_dev = hdev->id;
haddr->hci_channel= 0; haddr->hci_channel= hci_pi(sk)->channel;
done:
release_sock(sk); release_sock(sk);
return 0; return err;
} }
static void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, static void hci_sock_cmsg(struct sock *sk, struct msghdr *msg,
...@@ -767,6 +872,7 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -767,6 +872,7 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
case HCI_CHANNEL_RAW: case HCI_CHANNEL_RAW:
hci_sock_cmsg(sk, msg, skb); hci_sock_cmsg(sk, msg, skb);
break; break;
case HCI_CHANNEL_USER:
case HCI_CHANNEL_CONTROL: case HCI_CHANNEL_CONTROL:
case HCI_CHANNEL_MONITOR: case HCI_CHANNEL_MONITOR:
sock_recv_timestamp(msg, sk, skb); sock_recv_timestamp(msg, sk, skb);
...@@ -801,6 +907,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -801,6 +907,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
switch (hci_pi(sk)->channel) { switch (hci_pi(sk)->channel) {
case HCI_CHANNEL_RAW: case HCI_CHANNEL_RAW:
case HCI_CHANNEL_USER:
break; break;
case HCI_CHANNEL_CONTROL: case HCI_CHANNEL_CONTROL:
err = mgmt_control(sk, msg, len); err = mgmt_control(sk, msg, len);
...@@ -837,7 +944,8 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -837,7 +944,8 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
skb_pull(skb, 1); skb_pull(skb, 1);
skb->dev = (void *) hdev; skb->dev = (void *) hdev;
if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) { if (hci_pi(sk)->channel == HCI_CHANNEL_RAW &&
bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
u16 opcode = get_unaligned_le16(skb->data); u16 opcode = get_unaligned_le16(skb->data);
u16 ogf = hci_opcode_ogf(opcode); u16 ogf = hci_opcode_ogf(opcode);
u16 ocf = hci_opcode_ocf(opcode); u16 ocf = hci_opcode_ocf(opcode);
...@@ -868,6 +976,14 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -868,6 +976,14 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
goto drop; goto drop;
} }
if (hci_pi(sk)->channel == HCI_CHANNEL_USER &&
bt_cb(skb)->pkt_type != HCI_COMMAND_PKT &&
bt_cb(skb)->pkt_type != HCI_ACLDATA_PKT &&
bt_cb(skb)->pkt_type != HCI_SCODATA_PKT) {
err = -EINVAL;
goto drop;
}
skb_queue_tail(&hdev->raw_q, skb); skb_queue_tail(&hdev->raw_q, skb);
queue_work(hdev->workqueue, &hdev->tx_work); queue_work(hdev->workqueue, &hdev->tx_work);
} }
...@@ -895,7 +1011,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, ...@@ -895,7 +1011,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
lock_sock(sk); lock_sock(sk);
if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) { if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) {
err = -EINVAL; err = -EBADFD;
goto done; goto done;
} }
...@@ -981,7 +1097,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, ...@@ -981,7 +1097,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
lock_sock(sk); lock_sock(sk);
if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) { if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) {
err = -EINVAL; err = -EBADFD;
goto done; goto done;
} }
......
This diff is collapsed.
...@@ -445,11 +445,6 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ...@@ -445,11 +445,6 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
break; break;
case BT_CHANNEL_POLICY: case BT_CHANNEL_POLICY:
if (!enable_hs) {
err = -ENOPROTOOPT;
break;
}
if (put_user(chan->chan_policy, (u32 __user *) optval)) if (put_user(chan->chan_policy, (u32 __user *) optval))
err = -EFAULT; err = -EFAULT;
break; break;
...@@ -720,11 +715,6 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ...@@ -720,11 +715,6 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break; break;
case BT_CHANNEL_POLICY: case BT_CHANNEL_POLICY:
if (!enable_hs) {
err = -ENOPROTOOPT;
break;
}
if (get_user(opt, (u32 __user *) optval)) { if (get_user(opt, (u32 __user *) optval)) {
err = -EFAULT; err = -EFAULT;
break; break;
...@@ -777,6 +767,12 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -777,6 +767,12 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
if (sk->sk_state != BT_CONNECTED) if (sk->sk_state != BT_CONNECTED)
return -ENOTCONN; return -ENOTCONN;
lock_sock(sk);
err = bt_sock_wait_ready(sk, msg->msg_flags);
release_sock(sk);
if (err)
return err;
l2cap_chan_lock(chan); l2cap_chan_lock(chan);
err = l2cap_chan_send(chan, msg, len, sk->sk_priority); err = l2cap_chan_send(chan, msg, len, sk->sk_priority);
l2cap_chan_unlock(chan); l2cap_chan_unlock(chan);
...@@ -799,8 +795,8 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -799,8 +795,8 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
pi->chan->state = BT_CONFIG; pi->chan->state = BT_CONFIG;
__l2cap_connect_rsp_defer(pi->chan); __l2cap_connect_rsp_defer(pi->chan);
release_sock(sk); err = 0;
return 0; goto done;
} }
release_sock(sk); release_sock(sk);
......
This diff is collapsed.
...@@ -544,7 +544,7 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -544,7 +544,7 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc; struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
struct sk_buff *skb; struct sk_buff *skb;
int sent = 0; int sent;
if (test_bit(RFCOMM_DEFER_SETUP, &d->flags)) if (test_bit(RFCOMM_DEFER_SETUP, &d->flags))
return -ENOTCONN; return -ENOTCONN;
...@@ -559,6 +559,10 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -559,6 +559,10 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
lock_sock(sk); lock_sock(sk);
sent = bt_sock_wait_ready(sk, msg->msg_flags);
if (sent)
goto done;
while (len) { while (len) {
size_t size = min_t(size_t, len, d->mtu); size_t size = min_t(size_t, len, d->mtu);
int err; int err;
...@@ -594,6 +598,7 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -594,6 +598,7 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
len -= size; len -= size;
} }
done:
release_sock(sk); release_sock(sk);
return sent; return sent;
......
...@@ -569,7 +569,6 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb) ...@@ -569,7 +569,6 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
{ {
struct rfcomm_dev *dev = dlc->owner; struct rfcomm_dev *dev = dlc->owner;
struct tty_struct *tty;
if (!dev) if (!dev)
return; return;
...@@ -581,38 +580,8 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) ...@@ -581,38 +580,8 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
DPM_ORDER_DEV_AFTER_PARENT); DPM_ORDER_DEV_AFTER_PARENT);
wake_up_interruptible(&dev->port.open_wait); wake_up_interruptible(&dev->port.open_wait);
} else if (dlc->state == BT_CLOSED) { } else if (dlc->state == BT_CLOSED)
tty = tty_port_tty_get(&dev->port); tty_port_tty_hangup(&dev->port, false);
if (!tty) {
if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
/* Drop DLC lock here to avoid deadlock
* 1. rfcomm_dev_get will take rfcomm_dev_lock
* but in rfcomm_dev_add there's lock order:
* rfcomm_dev_lock -> dlc lock
* 2. tty_port_put will deadlock if it's
* the last reference
*
* FIXME: when we release the lock anything
* could happen to dev, even its destruction
*/
rfcomm_dlc_unlock(dlc);
if (rfcomm_dev_get(dev->id) == NULL) {
rfcomm_dlc_lock(dlc);
return;
}
if (!test_and_set_bit(RFCOMM_TTY_RELEASED,
&dev->flags))
tty_port_put(&dev->port);
tty_port_put(&dev->port);
rfcomm_dlc_lock(dlc);
}
} else {
tty_hangup(tty);
tty_kref_put(tty);
}
}
} }
static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig) static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
......
...@@ -847,16 +847,27 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -847,16 +847,27 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
{ {
__u8 code = skb->data[0]; struct hci_conn *hcon = conn->hcon;
__u8 reason; __u8 code, reason;
int err = 0; int err = 0;
if (hcon->type != LE_LINK) {
kfree_skb(skb);
return -ENOTSUPP;
}
if (skb->len < 1) {
kfree_skb(skb);
return -EILSEQ;
}
if (!test_bit(HCI_LE_ENABLED, &conn->hcon->hdev->dev_flags)) { if (!test_bit(HCI_LE_ENABLED, &conn->hcon->hdev->dev_flags)) {
err = -ENOTSUPP; err = -ENOTSUPP;
reason = SMP_PAIRING_NOTSUPP; reason = SMP_PAIRING_NOTSUPP;
goto done; goto done;
} }
code = skb->data[0];
skb_pull(skb, sizeof(code)); skb_pull(skb, sizeof(code));
/* /*
......
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