提交 f4f314bf 编写于 作者: J John W. Linville
...@@ -31,6 +31,30 @@ ...@@ -31,6 +31,30 @@
#define VERSION "1.0" #define VERSION "1.0"
#define ATH3K_DNLOAD 0x01
#define ATH3K_GETSTATE 0x05
#define ATH3K_SET_NORMAL_MODE 0x07
#define ATH3K_GETVERSION 0x09
#define USB_REG_SWITCH_VID_PID 0x0a
#define ATH3K_MODE_MASK 0x3F
#define ATH3K_NORMAL_MODE 0x0E
#define ATH3K_PATCH_UPDATE 0x80
#define ATH3K_SYSCFG_UPDATE 0x40
#define ATH3K_XTAL_FREQ_26M 0x00
#define ATH3K_XTAL_FREQ_40M 0x01
#define ATH3K_XTAL_FREQ_19P2 0x02
#define ATH3K_NAME_LEN 0xFF
struct ath3k_version {
unsigned int rom_version;
unsigned int build_version;
unsigned int ram_version;
unsigned char ref_clock;
unsigned char reserved[0x07];
};
static struct usb_device_id ath3k_table[] = { static struct usb_device_id ath3k_table[] = {
/* Atheros AR3011 */ /* Atheros AR3011 */
...@@ -41,13 +65,29 @@ static struct usb_device_id ath3k_table[] = { ...@@ -41,13 +65,29 @@ static struct usb_device_id ath3k_table[] = {
/* Atheros AR9285 Malbec with sflash firmware */ /* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03F0, 0x311D) }, { USB_DEVICE(0x03F0, 0x311D) },
/* Atheros AR3012 with sflash firmware*/
{ USB_DEVICE(0x0CF3, 0x3004) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
MODULE_DEVICE_TABLE(usb, ath3k_table); MODULE_DEVICE_TABLE(usb, ath3k_table);
#define BTUSB_ATH3012 0x80
/* This table is to load patch and sysconfig files
* for AR3012 */
static struct usb_device_id ath3k_blist_tbl[] = {
/* Atheros AR3012 with sflash firmware*/
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
{ } /* Terminating entry */
};
#define USB_REQ_DFU_DNLOAD 1 #define USB_REQ_DFU_DNLOAD 1
#define BULK_SIZE 4096 #define BULK_SIZE 4096
#define FW_HDR_SIZE 20
static int ath3k_load_firmware(struct usb_device *udev, static int ath3k_load_firmware(struct usb_device *udev,
const struct firmware *firmware) const struct firmware *firmware)
...@@ -103,6 +143,215 @@ static int ath3k_load_firmware(struct usb_device *udev, ...@@ -103,6 +143,215 @@ static int ath3k_load_firmware(struct usb_device *udev,
return err; return err;
} }
static int ath3k_get_state(struct usb_device *udev, unsigned char *state)
{
int pipe = 0;
pipe = usb_rcvctrlpipe(udev, 0);
return usb_control_msg(udev, pipe, ATH3K_GETSTATE,
USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
state, 0x01, USB_CTRL_SET_TIMEOUT);
}
static int ath3k_get_version(struct usb_device *udev,
struct ath3k_version *version)
{
int pipe = 0;
pipe = usb_rcvctrlpipe(udev, 0);
return usb_control_msg(udev, pipe, ATH3K_GETVERSION,
USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, version,
sizeof(struct ath3k_version),
USB_CTRL_SET_TIMEOUT);
}
static int ath3k_load_fwfile(struct usb_device *udev,
const struct firmware *firmware)
{
u8 *send_buf;
int err, pipe, len, size, count, sent = 0;
int ret;
count = firmware->size;
send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
if (!send_buf) {
BT_ERR("Can't allocate memory chunk for firmware");
return -ENOMEM;
}
size = min_t(uint, count, FW_HDR_SIZE);
memcpy(send_buf, firmware->data, size);
pipe = usb_sndctrlpipe(udev, 0);
ret = usb_control_msg(udev, pipe, ATH3K_DNLOAD,
USB_TYPE_VENDOR, 0, 0, send_buf,
size, USB_CTRL_SET_TIMEOUT);
if (ret < 0) {
BT_ERR("Can't change to loading configuration err");
kfree(send_buf);
return ret;
}
sent += size;
count -= size;
while (count) {
size = min_t(uint, count, BULK_SIZE);
pipe = usb_sndbulkpipe(udev, 0x02);
memcpy(send_buf, firmware->data + sent, size);
err = usb_bulk_msg(udev, pipe, send_buf, size,
&len, 3000);
if (err || (len != size)) {
BT_ERR("Error in firmware loading err = %d,"
"len = %d, size = %d", err, len, size);
kfree(send_buf);
return err;
}
sent += size;
count -= size;
}
kfree(send_buf);
return 0;
}
static int ath3k_switch_pid(struct usb_device *udev)
{
int pipe = 0;
pipe = usb_sndctrlpipe(udev, 0);
return usb_control_msg(udev, pipe, USB_REG_SWITCH_VID_PID,
USB_TYPE_VENDOR, 0, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
}
static int ath3k_set_normal_mode(struct usb_device *udev)
{
unsigned char fw_state;
int pipe = 0, ret;
ret = ath3k_get_state(udev, &fw_state);
if (ret < 0) {
BT_ERR("Can't get state to change to normal mode err");
return ret;
}
if ((fw_state & ATH3K_MODE_MASK) == ATH3K_NORMAL_MODE) {
BT_DBG("firmware was already in normal mode");
return 0;
}
pipe = usb_sndctrlpipe(udev, 0);
return usb_control_msg(udev, pipe, ATH3K_SET_NORMAL_MODE,
USB_TYPE_VENDOR, 0, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
}
static int ath3k_load_patch(struct usb_device *udev)
{
unsigned char fw_state;
char filename[ATH3K_NAME_LEN] = {0};
const struct firmware *firmware;
struct ath3k_version fw_version, pt_version;
int ret;
ret = ath3k_get_state(udev, &fw_state);
if (ret < 0) {
BT_ERR("Can't get state to change to load ram patch err");
return ret;
}
if (fw_state & ATH3K_PATCH_UPDATE) {
BT_DBG("Patch was already downloaded");
return 0;
}
ret = ath3k_get_version(udev, &fw_version);
if (ret < 0) {
BT_ERR("Can't get version to change to load ram patch err");
return ret;
}
snprintf(filename, ATH3K_NAME_LEN, "ar3k/AthrBT_0x%08x.dfu",
fw_version.rom_version);
ret = request_firmware(&firmware, filename, &udev->dev);
if (ret < 0) {
BT_ERR("Patch file not found %s", filename);
return ret;
}
pt_version.rom_version = *(int *)(firmware->data + firmware->size - 8);
pt_version.build_version = *(int *)
(firmware->data + firmware->size - 4);
if ((pt_version.rom_version != fw_version.rom_version) ||
(pt_version.build_version <= fw_version.build_version)) {
BT_ERR("Patch file version did not match with firmware");
release_firmware(firmware);
return -EINVAL;
}
ret = ath3k_load_fwfile(udev, firmware);
release_firmware(firmware);
return ret;
}
static int ath3k_load_syscfg(struct usb_device *udev)
{
unsigned char fw_state;
char filename[ATH3K_NAME_LEN] = {0};
const struct firmware *firmware;
struct ath3k_version fw_version;
int clk_value, ret;
ret = ath3k_get_state(udev, &fw_state);
if (ret < 0) {
BT_ERR("Can't get state to change to load configration err");
return -EBUSY;
}
ret = ath3k_get_version(udev, &fw_version);
if (ret < 0) {
BT_ERR("Can't get version to change to load ram patch err");
return ret;
}
switch (fw_version.ref_clock) {
case ATH3K_XTAL_FREQ_26M:
clk_value = 26;
break;
case ATH3K_XTAL_FREQ_40M:
clk_value = 40;
break;
case ATH3K_XTAL_FREQ_19P2:
clk_value = 19;
break;
default:
clk_value = 0;
break;
}
snprintf(filename, ATH3K_NAME_LEN, "ar3k/ramps_0x%08x_%d%s",
fw_version.rom_version, clk_value, ".dfu");
ret = request_firmware(&firmware, filename, &udev->dev);
if (ret < 0) {
BT_ERR("Configuration file not found %s", filename);
return ret;
}
ret = ath3k_load_fwfile(udev, firmware);
release_firmware(firmware);
return ret;
}
static int ath3k_probe(struct usb_interface *intf, static int ath3k_probe(struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
...@@ -115,7 +364,37 @@ static int ath3k_probe(struct usb_interface *intf, ...@@ -115,7 +364,37 @@ static int ath3k_probe(struct usb_interface *intf,
if (intf->cur_altsetting->desc.bInterfaceNumber != 0) if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV; return -ENODEV;
/* match device ID in ath3k blacklist table */
if (!id->driver_info) {
const struct usb_device_id *match;
match = usb_match_id(intf, ath3k_blist_tbl);
if (match)
id = match;
}
/* load patch and sysconfig files for AR3012 */
if (id->driver_info & BTUSB_ATH3012) {
ret = ath3k_load_patch(udev);
if (ret < 0) {
BT_ERR("Loading patch file failed");
return ret;
}
ret = ath3k_load_syscfg(udev);
if (ret < 0) {
BT_ERR("Loading sysconfig file failed");
return ret;
}
ret = ath3k_set_normal_mode(udev);
if (ret < 0) {
BT_ERR("Set normal mode failed");
return ret;
}
ath3k_switch_pid(udev);
return 0;
}
if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) { if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
BT_ERR("Error loading firmware");
return -EIO; return -EIO;
} }
......
...@@ -105,6 +105,9 @@ static struct usb_device_id blacklist_table[] = { ...@@ -105,6 +105,9 @@ static struct usb_device_id blacklist_table[] = {
/* Atheros AR9285 Malbec with sflash firmware */ /* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
/* Atheros 3012 with sflash firmware */
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_IGNORE },
/* Broadcom BCM2035 */ /* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
...@@ -711,15 +714,11 @@ static int btusb_send_frame(struct sk_buff *skb) ...@@ -711,15 +714,11 @@ static int btusb_send_frame(struct sk_buff *skb)
pipe = usb_sndisocpipe(data->udev, pipe = usb_sndisocpipe(data->udev,
data->isoc_tx_ep->bEndpointAddress); data->isoc_tx_ep->bEndpointAddress);
urb->dev = data->udev; usb_fill_int_urb(urb, data->udev, pipe,
urb->pipe = pipe; skb->data, skb->len, btusb_isoc_tx_complete,
urb->context = skb; skb, data->isoc_tx_ep->bInterval);
urb->complete = btusb_isoc_tx_complete;
urb->interval = data->isoc_tx_ep->bInterval;
urb->transfer_flags = URB_ISO_ASAP; urb->transfer_flags = URB_ISO_ASAP;
urb->transfer_buffer = skb->data;
urb->transfer_buffer_length = skb->len;
__fill_isoc_descriptor(urb, skb->len, __fill_isoc_descriptor(urb, skb->len,
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
......
...@@ -398,6 +398,7 @@ static int hci_uart_register_dev(struct hci_uart *hu) ...@@ -398,6 +398,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
hdev->flush = hci_uart_flush; hdev->flush = hci_uart_flush;
hdev->send = hci_uart_send_frame; hdev->send = hci_uart_send_frame;
hdev->destruct = hci_uart_destruct; hdev->destruct = hci_uart_destruct;
hdev->parent = hu->tty->dev;
hdev->owner = THIS_MODULE; hdev->owner = THIS_MODULE;
......
...@@ -205,4 +205,32 @@ extern void bt_sysfs_cleanup(void); ...@@ -205,4 +205,32 @@ extern void bt_sysfs_cleanup(void);
extern struct dentry *bt_debugfs; extern struct dentry *bt_debugfs;
#ifdef CONFIG_BT_L2CAP
int l2cap_init(void);
void l2cap_exit(void);
#else
static inline int l2cap_init(void)
{
return 0;
}
static inline void l2cap_exit(void)
{
}
#endif
#ifdef CONFIG_BT_SCO
int sco_init(void);
void sco_exit(void);
#else
static inline int sco_init(void)
{
return 0;
}
static inline void sco_exit(void)
{
}
#endif
#endif /* __BLUETOOTH_H */ #endif /* __BLUETOOTH_H */
...@@ -119,6 +119,7 @@ enum { ...@@ -119,6 +119,7 @@ enum {
#define HCI_PAIRING_TIMEOUT (60000) /* 60 seconds */ #define HCI_PAIRING_TIMEOUT (60000) /* 60 seconds */
#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */ #define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */
#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */ #define HCI_INIT_TIMEOUT (10000) /* 10 seconds */
#define HCI_CMD_TIMEOUT (1000) /* 1 seconds */
/* HCI data types */ /* HCI data types */
#define HCI_COMMAND_PKT 0x01 #define HCI_COMMAND_PKT 0x01
...@@ -168,6 +169,8 @@ enum { ...@@ -168,6 +169,8 @@ enum {
#define SCO_LINK 0x00 #define SCO_LINK 0x00
#define ACL_LINK 0x01 #define ACL_LINK 0x01
#define ESCO_LINK 0x02 #define ESCO_LINK 0x02
/* Low Energy links do not have defined link type. Use invented one */
#define LE_LINK 0x80
/* LMP features */ /* LMP features */
#define LMP_3SLOT 0x01 #define LMP_3SLOT 0x01
...@@ -242,6 +245,8 @@ enum { ...@@ -242,6 +245,8 @@ enum {
#define HCI_AT_GENERAL_BONDING_MITM 0x05 #define HCI_AT_GENERAL_BONDING_MITM 0x05
/* ----- HCI Commands ---- */ /* ----- HCI Commands ---- */
#define HCI_OP_NOP 0x0000
#define HCI_OP_INQUIRY 0x0401 #define HCI_OP_INQUIRY 0x0401
struct hci_cp_inquiry { struct hci_cp_inquiry {
__u8 lap[3]; __u8 lap[3];
...@@ -642,6 +647,47 @@ struct hci_rp_read_bd_addr { ...@@ -642,6 +647,47 @@ struct hci_rp_read_bd_addr {
bdaddr_t bdaddr; bdaddr_t bdaddr;
} __packed; } __packed;
#define HCI_OP_LE_SET_EVENT_MASK 0x2001
struct hci_cp_le_set_event_mask {
__u8 mask[8];
} __packed;
#define HCI_OP_LE_READ_BUFFER_SIZE 0x2002
struct hci_rp_le_read_buffer_size {
__u8 status;
__le16 le_mtu;
__u8 le_max_pkt;
} __packed;
#define HCI_OP_LE_CREATE_CONN 0x200d
struct hci_cp_le_create_conn {
__le16 scan_interval;
__le16 scan_window;
__u8 filter_policy;
__u8 peer_addr_type;
bdaddr_t peer_addr;
__u8 own_address_type;
__le16 conn_interval_min;
__le16 conn_interval_max;
__le16 conn_latency;
__le16 supervision_timeout;
__le16 min_ce_len;
__le16 max_ce_len;
} __packed;
#define HCI_OP_LE_CREATE_CONN_CANCEL 0x200e
#define HCI_OP_LE_CONN_UPDATE 0x2013
struct hci_cp_le_conn_update {
__le16 handle;
__le16 conn_interval_min;
__le16 conn_interval_max;
__le16 conn_latency;
__le16 supervision_timeout;
__le16 min_ce_len;
__le16 max_ce_len;
} __packed;
/* ---- HCI Events ---- */ /* ---- HCI Events ---- */
#define HCI_EV_INQUIRY_COMPLETE 0x01 #define HCI_EV_INQUIRY_COMPLETE 0x01
...@@ -902,6 +948,25 @@ struct hci_ev_remote_host_features { ...@@ -902,6 +948,25 @@ struct hci_ev_remote_host_features {
__u8 features[8]; __u8 features[8];
} __packed; } __packed;
#define HCI_EV_LE_META 0x3e
struct hci_ev_le_meta {
__u8 subevent;
} __packed;
/* Low energy meta events */
#define HCI_EV_LE_CONN_COMPLETE 0x01
struct hci_ev_le_conn_complete {
__u8 status;
__le16 handle;
__u8 role;
__u8 bdaddr_type;
bdaddr_t bdaddr;
__le16 interval;
__le16 latency;
__le16 supervision_timeout;
__u8 clk_accurancy;
} __packed;
/* Internal events generated by Bluetooth stack */ /* Internal events generated by Bluetooth stack */
#define HCI_EV_STACK_INTERNAL 0xfd #define HCI_EV_STACK_INTERNAL 0xfd
struct hci_ev_stack_internal { struct hci_ev_stack_internal {
......
...@@ -60,6 +60,7 @@ struct hci_conn_hash { ...@@ -60,6 +60,7 @@ struct hci_conn_hash {
spinlock_t lock; spinlock_t lock;
unsigned int acl_num; unsigned int acl_num;
unsigned int sco_num; unsigned int sco_num;
unsigned int le_num;
}; };
struct bdaddr_list { struct bdaddr_list {
...@@ -122,15 +123,18 @@ struct hci_dev { ...@@ -122,15 +123,18 @@ struct hci_dev {
atomic_t cmd_cnt; atomic_t cmd_cnt;
unsigned int acl_cnt; unsigned int acl_cnt;
unsigned int sco_cnt; unsigned int sco_cnt;
unsigned int le_cnt;
unsigned int acl_mtu; unsigned int acl_mtu;
unsigned int sco_mtu; unsigned int sco_mtu;
unsigned int le_mtu;
unsigned int acl_pkts; unsigned int acl_pkts;
unsigned int sco_pkts; unsigned int sco_pkts;
unsigned int le_pkts;
unsigned long cmd_last_tx;
unsigned long acl_last_tx; unsigned long acl_last_tx;
unsigned long sco_last_tx; unsigned long sco_last_tx;
unsigned long le_last_tx;
struct workqueue_struct *workqueue; struct workqueue_struct *workqueue;
...@@ -138,6 +142,7 @@ struct hci_dev { ...@@ -138,6 +142,7 @@ struct hci_dev {
struct work_struct power_off; struct work_struct power_off;
struct timer_list off_timer; struct timer_list off_timer;
struct timer_list cmd_timer;
struct tasklet_struct cmd_task; struct tasklet_struct cmd_task;
struct tasklet_struct rx_task; struct tasklet_struct rx_task;
struct tasklet_struct tx_task; struct tasklet_struct tx_task;
...@@ -194,37 +199,37 @@ struct hci_dev { ...@@ -194,37 +199,37 @@ struct hci_dev {
struct hci_conn { struct hci_conn {
struct list_head list; struct list_head list;
atomic_t refcnt; atomic_t refcnt;
spinlock_t lock; spinlock_t lock;
bdaddr_t dst; bdaddr_t dst;
__u16 handle; __u16 handle;
__u16 state; __u16 state;
__u8 mode; __u8 mode;
__u8 type; __u8 type;
__u8 out; __u8 out;
__u8 attempt; __u8 attempt;
__u8 dev_class[3]; __u8 dev_class[3];
__u8 features[8]; __u8 features[8];
__u8 ssp_mode; __u8 ssp_mode;
__u16 interval; __u16 interval;
__u16 pkt_type; __u16 pkt_type;
__u16 link_policy; __u16 link_policy;
__u32 link_mode; __u32 link_mode;
__u8 auth_type; __u8 auth_type;
__u8 sec_level; __u8 sec_level;
__u8 pending_sec_level; __u8 pending_sec_level;
__u8 pin_length; __u8 pin_length;
__u8 io_capability; __u8 io_capability;
__u8 power_save; __u8 power_save;
__u16 disc_timeout; __u16 disc_timeout;
unsigned long pend; unsigned long pend;
__u8 remote_cap; __u8 remote_cap;
__u8 remote_oob; __u8 remote_oob;
__u8 remote_auth; __u8 remote_auth;
unsigned int sent; unsigned int sent;
struct sk_buff_head data_q; struct sk_buff_head data_q;
...@@ -309,24 +314,40 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) ...@@ -309,24 +314,40 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
{ {
struct hci_conn_hash *h = &hdev->conn_hash; struct hci_conn_hash *h = &hdev->conn_hash;
list_add(&c->list, &h->list); list_add(&c->list, &h->list);
if (c->type == ACL_LINK) switch (c->type) {
case ACL_LINK:
h->acl_num++; h->acl_num++;
else break;
case LE_LINK:
h->le_num++;
break;
case SCO_LINK:
case ESCO_LINK:
h->sco_num++; h->sco_num++;
break;
}
} }
static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
{ {
struct hci_conn_hash *h = &hdev->conn_hash; struct hci_conn_hash *h = &hdev->conn_hash;
list_del(&c->list); list_del(&c->list);
if (c->type == ACL_LINK) switch (c->type) {
case ACL_LINK:
h->acl_num--; h->acl_num--;
else break;
case LE_LINK:
h->le_num--;
break;
case SCO_LINK:
case ESCO_LINK:
h->sco_num--; h->sco_num--;
break;
}
} }
static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev, static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
__u16 handle) __u16 handle)
{ {
struct hci_conn_hash *h = &hdev->conn_hash; struct hci_conn_hash *h = &hdev->conn_hash;
struct list_head *p; struct list_head *p;
...@@ -341,7 +362,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev, ...@@ -341,7 +362,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
} }
static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev, static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
__u8 type, bdaddr_t *ba) __u8 type, bdaddr_t *ba)
{ {
struct hci_conn_hash *h = &hdev->conn_hash; struct hci_conn_hash *h = &hdev->conn_hash;
struct list_head *p; struct list_head *p;
...@@ -356,7 +377,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev, ...@@ -356,7 +377,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
} }
static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
__u8 type, __u16 state) __u8 type, __u16 state)
{ {
struct hci_conn_hash *h = &hdev->conn_hash; struct hci_conn_hash *h = &hdev->conn_hash;
struct list_head *p; struct list_head *p;
...@@ -504,6 +525,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn); ...@@ -504,6 +525,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO) #define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO)
#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR) #define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR)
#define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH) #define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH)
#define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE)
/* ----- HCI protocols ----- */ /* ----- HCI protocols ----- */
struct hci_proto { struct hci_proto {
...@@ -755,4 +777,6 @@ struct hci_sec_filter { ...@@ -755,4 +777,6 @@ struct hci_sec_filter {
void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result); void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result);
void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
u16 latency, u16 to_multiplier);
#endif /* __HCI_CORE_H */ #endif /* __HCI_CORE_H */
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */ #define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */
#define L2CAP_DEFAULT_ACK_TO 200 #define L2CAP_DEFAULT_ACK_TO 200
#define L2CAP_LOCAL_BUSY_TRIES 12 #define L2CAP_LOCAL_BUSY_TRIES 12
#define L2CAP_LE_DEFAULT_MTU 23
#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ #define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */
#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */ #define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */
...@@ -88,6 +89,8 @@ struct l2cap_conninfo { ...@@ -88,6 +89,8 @@ struct l2cap_conninfo {
#define L2CAP_ECHO_RSP 0x09 #define L2CAP_ECHO_RSP 0x09
#define L2CAP_INFO_REQ 0x0a #define L2CAP_INFO_REQ 0x0a
#define L2CAP_INFO_RSP 0x0b #define L2CAP_INFO_RSP 0x0b
#define L2CAP_CONN_PARAM_UPDATE_REQ 0x12
#define L2CAP_CONN_PARAM_UPDATE_RSP 0x13
/* L2CAP feature mask */ /* L2CAP feature mask */
#define L2CAP_FEAT_FLOWCTL 0x00000001 #define L2CAP_FEAT_FLOWCTL 0x00000001
...@@ -160,6 +163,9 @@ struct l2cap_conn_rsp { ...@@ -160,6 +163,9 @@ struct l2cap_conn_rsp {
/* channel indentifier */ /* channel indentifier */
#define L2CAP_CID_SIGNALING 0x0001 #define L2CAP_CID_SIGNALING 0x0001
#define L2CAP_CID_CONN_LESS 0x0002 #define L2CAP_CID_CONN_LESS 0x0002
#define L2CAP_CID_LE_DATA 0x0004
#define L2CAP_CID_LE_SIGNALING 0x0005
#define L2CAP_CID_SMP 0x0006
#define L2CAP_CID_DYN_START 0x0040 #define L2CAP_CID_DYN_START 0x0040
#define L2CAP_CID_DYN_END 0xffff #define L2CAP_CID_DYN_END 0xffff
...@@ -255,6 +261,21 @@ struct l2cap_info_rsp { ...@@ -255,6 +261,21 @@ struct l2cap_info_rsp {
#define L2CAP_IR_SUCCESS 0x0000 #define L2CAP_IR_SUCCESS 0x0000
#define L2CAP_IR_NOTSUPP 0x0001 #define L2CAP_IR_NOTSUPP 0x0001
struct l2cap_conn_param_update_req {
__le16 min;
__le16 max;
__le16 latency;
__le16 to_multiplier;
} __packed;
struct l2cap_conn_param_update_rsp {
__le16 result;
} __packed;
/* Connection Parameters result */
#define L2CAP_CONN_PARAM_ACCEPTED 0x0000
#define L2CAP_CONN_PARAM_REJECTED 0x0001
/* ----- L2CAP connections ----- */ /* ----- L2CAP connections ----- */
struct l2cap_chan_list { struct l2cap_chan_list {
struct sock *head; struct sock *head;
...@@ -455,6 +476,4 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err); ...@@ -455,6 +476,4 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err);
void l2cap_chan_del(struct sock *sk, int err); void l2cap_chan_del(struct sock *sk, int err);
int l2cap_do_connect(struct sock *sk); int l2cap_do_connect(struct sock *sk);
void l2cap_load(void);
#endif /* __L2CAP_H */ #endif /* __L2CAP_H */
#ifndef __SMP_H
#define __SMP_H
struct smp_command_hdr {
__u8 code;
} __packed;
#define SMP_CMD_PAIRING_REQ 0x01
#define SMP_CMD_PAIRING_RSP 0x02
struct smp_cmd_pairing {
__u8 io_capability;
__u8 oob_flag;
__u8 auth_req;
__u8 max_key_size;
__u8 init_key_dist;
__u8 resp_key_dist;
} __packed;
#define SMP_CMD_PAIRING_CONFIRM 0x03
struct smp_cmd_pairing_confirm {
__u8 confirm_val[16];
} __packed;
#define SMP_CMD_PAIRING_RANDOM 0x04
struct smp_cmd_pairing_random {
__u8 rand_val[16];
} __packed;
#define SMP_CMD_PAIRING_FAIL 0x05
struct smp_cmd_pairing_fail {
__u8 reason;
} __packed;
#define SMP_CMD_ENCRYPT_INFO 0x06
struct smp_cmd_encrypt_info {
__u8 ltk[16];
} __packed;
#define SMP_CMD_MASTER_IDENT 0x07
struct smp_cmd_master_ident {
__u16 ediv;
__u8 rand[8];
} __packed;
#define SMP_CMD_IDENT_INFO 0x08
struct smp_cmd_ident_info {
__u8 irk[16];
} __packed;
#define SMP_CMD_IDENT_ADDR_INFO 0x09
struct smp_cmd_ident_addr_info {
__u8 addr_type;
bdaddr_t bdaddr;
} __packed;
#define SMP_CMD_SIGN_INFO 0x0a
struct smp_cmd_sign_info {
__u8 csrk[16];
} __packed;
#define SMP_CMD_SECURITY_REQ 0x0b
struct smp_cmd_security_req {
__u8 auth_req;
} __packed;
#define SMP_PASSKEY_ENTRY_FAILED 0x01
#define SMP_OOB_NOT_AVAIL 0x02
#define SMP_AUTH_REQUIREMENTS 0x03
#define SMP_CONFIRM_FAILED 0x04
#define SMP_PAIRING_NOTSUPP 0x05
#define SMP_ENC_KEY_SIZE 0x06
#define SMP_CMD_NOTSUPP 0x07
#define SMP_UNSPECIFIED 0x08
#define SMP_REPEATED_ATTEMPTS 0x09
#endif /* __SMP_H */
...@@ -32,7 +32,7 @@ menuconfig BT ...@@ -32,7 +32,7 @@ menuconfig BT
more information, see <http://www.bluez.org/>. more information, see <http://www.bluez.org/>.
config BT_L2CAP config BT_L2CAP
tristate "L2CAP protocol support" bool "L2CAP protocol support"
depends on BT depends on BT
select CRC16 select CRC16
help help
...@@ -40,19 +40,13 @@ config BT_L2CAP ...@@ -40,19 +40,13 @@ config BT_L2CAP
connection oriented and connection-less data transport. L2CAP connection oriented and connection-less data transport. L2CAP
support is required for most Bluetooth applications. support is required for most Bluetooth applications.
Say Y here to compile L2CAP support into the kernel or say M to
compile it as module (l2cap).
config BT_SCO config BT_SCO
tristate "SCO links support" bool "SCO links support"
depends on BT depends on BT
help help
SCO link provides voice transport over Bluetooth. SCO support is SCO link provides voice transport over Bluetooth. SCO support is
required for voice applications like Headset and Audio. required for voice applications like Headset and Audio.
Say Y here to compile SCO support into the kernel or say M to
compile it as module (sco).
source "net/bluetooth/rfcomm/Kconfig" source "net/bluetooth/rfcomm/Kconfig"
source "net/bluetooth/bnep/Kconfig" source "net/bluetooth/bnep/Kconfig"
......
...@@ -3,12 +3,11 @@ ...@@ -3,12 +3,11 @@
# #
obj-$(CONFIG_BT) += bluetooth.o obj-$(CONFIG_BT) += bluetooth.o
obj-$(CONFIG_BT_L2CAP) += l2cap.o
obj-$(CONFIG_BT_SCO) += sco.o
obj-$(CONFIG_BT_RFCOMM) += rfcomm/ obj-$(CONFIG_BT_RFCOMM) += rfcomm/
obj-$(CONFIG_BT_BNEP) += bnep/ obj-$(CONFIG_BT_BNEP) += bnep/
obj-$(CONFIG_BT_CMTP) += cmtp/ obj-$(CONFIG_BT_CMTP) += cmtp/
obj-$(CONFIG_BT_HIDP) += hidp/ obj-$(CONFIG_BT_HIDP) += hidp/
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o hci_sock.o hci_sysfs.o lib.o bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o hci_sock.o hci_sysfs.o lib.o
l2cap-y := l2cap_core.o l2cap_sock.o bluetooth-$(CONFIG_BT_L2CAP) += l2cap_core.o l2cap_sock.o
bluetooth-$(CONFIG_BT_SCO) += sco.o
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#define VERSION "2.15" #define VERSION "2.16"
/* Bluetooth sockets */ /* Bluetooth sockets */
#define BT_MAX_PROTO 8 #define BT_MAX_PROTO 8
...@@ -397,7 +397,7 @@ static inline unsigned int bt_accept_poll(struct sock *parent) ...@@ -397,7 +397,7 @@ static inline unsigned int bt_accept_poll(struct sock *parent)
return 0; return 0;
} }
unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait) unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
unsigned int mask = 0; unsigned int mask = 0;
...@@ -545,13 +545,41 @@ static int __init bt_init(void) ...@@ -545,13 +545,41 @@ static int __init bt_init(void)
BT_INFO("HCI device and connection manager initialized"); BT_INFO("HCI device and connection manager initialized");
hci_sock_init(); err = hci_sock_init();
if (err < 0)
goto error;
err = l2cap_init();
if (err < 0) {
hci_sock_cleanup();
goto sock_err;
}
err = sco_init();
if (err < 0) {
l2cap_exit();
goto sock_err;
}
return 0; return 0;
sock_err:
hci_sock_cleanup();
error:
sock_unregister(PF_BLUETOOTH);
bt_sysfs_cleanup();
return err;
} }
static void __exit bt_exit(void) static void __exit bt_exit(void)
{ {
sco_exit();
l2cap_exit();
hci_sock_cleanup(); hci_sock_cleanup();
sock_unregister(PF_BLUETOOTH); sock_unregister(PF_BLUETOOTH);
......
...@@ -708,8 +708,6 @@ static int __init bnep_init(void) ...@@ -708,8 +708,6 @@ static int __init bnep_init(void)
{ {
char flt[50] = ""; char flt[50] = "";
l2cap_load();
#ifdef CONFIG_BT_BNEP_PROTO_FILTER #ifdef CONFIG_BT_BNEP_PROTO_FILTER
strcat(flt, "protocol "); strcat(flt, "protocol ");
#endif #endif
......
...@@ -88,6 +88,7 @@ static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long ...@@ -88,6 +88,7 @@ static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
sockfd_put(nsock); sockfd_put(nsock);
return -EBADFD; return -EBADFD;
} }
ca.device[sizeof(ca.device)-1] = 0;
err = bnep_add_connection(&ca, nsock); err = bnep_add_connection(&ca, nsock);
if (!err) { if (!err) {
......
...@@ -469,8 +469,6 @@ int cmtp_get_conninfo(struct cmtp_conninfo *ci) ...@@ -469,8 +469,6 @@ int cmtp_get_conninfo(struct cmtp_conninfo *ci)
static int __init cmtp_init(void) static int __init cmtp_init(void)
{ {
l2cap_load();
BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION); BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION);
cmtp_init_sockets(); cmtp_init_sockets();
......
...@@ -45,6 +45,33 @@ ...@@ -45,6 +45,33 @@
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
static void hci_le_connect(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_create_conn cp;
conn->state = BT_CONNECT;
conn->out = 1;
conn->link_mode |= HCI_LM_MASTER;
memset(&cp, 0, sizeof(cp));
cp.scan_interval = cpu_to_le16(0x0004);
cp.scan_window = cpu_to_le16(0x0004);
bacpy(&cp.peer_addr, &conn->dst);
cp.conn_interval_min = cpu_to_le16(0x0008);
cp.conn_interval_max = cpu_to_le16(0x0100);
cp.supervision_timeout = cpu_to_le16(0x0064);
cp.min_ce_len = cpu_to_le16(0x0001);
cp.max_ce_len = cpu_to_le16(0x0001);
hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
}
static void hci_le_connect_cancel(struct hci_conn *conn)
{
hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
}
void hci_acl_connect(struct hci_conn *conn) void hci_acl_connect(struct hci_conn *conn)
{ {
struct hci_dev *hdev = conn->hdev; struct hci_dev *hdev = conn->hdev;
...@@ -156,6 +183,26 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) ...@@ -156,6 +183,26 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp); hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
} }
void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
u16 latency, u16 to_multiplier)
{
struct hci_cp_le_conn_update cp;
struct hci_dev *hdev = conn->hdev;
memset(&cp, 0, sizeof(cp));
cp.handle = cpu_to_le16(conn->handle);
cp.conn_interval_min = cpu_to_le16(min);
cp.conn_interval_max = cpu_to_le16(max);
cp.conn_latency = cpu_to_le16(latency);
cp.supervision_timeout = cpu_to_le16(to_multiplier);
cp.min_ce_len = cpu_to_le16(0x0001);
cp.max_ce_len = cpu_to_le16(0x0001);
hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp);
}
EXPORT_SYMBOL(hci_le_conn_update);
/* Device _must_ be locked */ /* Device _must_ be locked */
void hci_sco_setup(struct hci_conn *conn, __u8 status) void hci_sco_setup(struct hci_conn *conn, __u8 status)
{ {
...@@ -193,8 +240,12 @@ static void hci_conn_timeout(unsigned long arg) ...@@ -193,8 +240,12 @@ static void hci_conn_timeout(unsigned long arg)
switch (conn->state) { switch (conn->state) {
case BT_CONNECT: case BT_CONNECT:
case BT_CONNECT2: case BT_CONNECT2:
if (conn->type == ACL_LINK && conn->out) if (conn->out) {
hci_acl_connect_cancel(conn); if (conn->type == ACL_LINK)
hci_acl_connect_cancel(conn);
else if (conn->type == LE_LINK)
hci_le_connect_cancel(conn);
}
break; break;
case BT_CONFIG: case BT_CONFIG:
case BT_CONNECTED: case BT_CONNECTED:
...@@ -296,6 +347,11 @@ int hci_conn_del(struct hci_conn *conn) ...@@ -296,6 +347,11 @@ int hci_conn_del(struct hci_conn *conn)
/* Unacked frames */ /* Unacked frames */
hdev->acl_cnt += conn->sent; hdev->acl_cnt += conn->sent;
} else if (conn->type == LE_LINK) {
if (hdev->le_pkts)
hdev->le_cnt += conn->sent;
else
hdev->acl_cnt += conn->sent;
} else { } else {
struct hci_conn *acl = conn->link; struct hci_conn *acl = conn->link;
if (acl) { if (acl) {
...@@ -361,15 +417,30 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) ...@@ -361,15 +417,30 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
} }
EXPORT_SYMBOL(hci_get_route); EXPORT_SYMBOL(hci_get_route);
/* Create SCO or ACL connection. /* Create SCO, ACL or LE connection.
* Device _must_ be locked */ * Device _must_ be locked */
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type) struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type)
{ {
struct hci_conn *acl; struct hci_conn *acl;
struct hci_conn *sco; struct hci_conn *sco;
struct hci_conn *le;
BT_DBG("%s dst %s", hdev->name, batostr(dst)); BT_DBG("%s dst %s", hdev->name, batostr(dst));
if (type == LE_LINK) {
le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
if (!le)
le = hci_conn_add(hdev, LE_LINK, dst);
if (!le)
return NULL;
if (le->state == BT_OPEN)
hci_le_connect(le);
hci_conn_hold(le);
return le;
}
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);
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/rfkill.h> #include <linux/rfkill.h>
#include <linux/timer.h>
#include <net/sock.h> #include <net/sock.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -123,7 +124,7 @@ static void hci_req_cancel(struct hci_dev *hdev, int err) ...@@ -123,7 +124,7 @@ static void hci_req_cancel(struct hci_dev *hdev, int err)
/* Execute request and wait for completion. */ /* Execute request and wait for completion. */
static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
unsigned long opt, __u32 timeout) unsigned long opt, __u32 timeout)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
int err = 0; int err = 0;
...@@ -165,7 +166,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, ...@@ -165,7 +166,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
} }
static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
unsigned long opt, __u32 timeout) unsigned long opt, __u32 timeout)
{ {
int ret; int ret;
...@@ -263,6 +264,14 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) ...@@ -263,6 +264,14 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp); hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
} }
static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt)
{
BT_DBG("%s", hdev->name);
/* Read LE buffer size */
hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
}
static void hci_scan_req(struct hci_dev *hdev, unsigned long opt) static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
{ {
__u8 scan = opt; __u8 scan = opt;
...@@ -456,7 +465,7 @@ int hci_inquiry(void __user *arg) ...@@ -456,7 +465,7 @@ int hci_inquiry(void __user *arg)
/* cache_dump can't sleep. Therefore we allocate temp buffer and then /* cache_dump can't sleep. Therefore we allocate temp buffer and then
* copy it to the user space. * copy it to the user space.
*/ */
buf = kmalloc(sizeof(struct inquiry_info) *max_rsp, GFP_KERNEL); buf = kmalloc(sizeof(struct inquiry_info) * max_rsp, GFP_KERNEL);
if (!buf) { if (!buf) {
err = -ENOMEM; err = -ENOMEM;
goto done; goto done;
...@@ -525,10 +534,13 @@ int hci_dev_open(__u16 dev) ...@@ -525,10 +534,13 @@ int hci_dev_open(__u16 dev)
set_bit(HCI_INIT, &hdev->flags); set_bit(HCI_INIT, &hdev->flags);
hdev->init_last_cmd = 0; hdev->init_last_cmd = 0;
//__hci_request(hdev, hci_reset_req, 0, HZ);
ret = __hci_request(hdev, hci_init_req, 0, ret = __hci_request(hdev, hci_init_req, 0,
msecs_to_jiffies(HCI_INIT_TIMEOUT)); msecs_to_jiffies(HCI_INIT_TIMEOUT));
if (lmp_le_capable(hdev))
ret = __hci_request(hdev, hci_le_init_req, 0,
msecs_to_jiffies(HCI_INIT_TIMEOUT));
clear_bit(HCI_INIT, &hdev->flags); clear_bit(HCI_INIT, &hdev->flags);
} }
...@@ -611,6 +623,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) ...@@ -611,6 +623,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
/* Drop last sent command */ /* Drop last sent command */
if (hdev->sent_cmd) { if (hdev->sent_cmd) {
del_timer_sync(&hdev->cmd_timer);
kfree_skb(hdev->sent_cmd); kfree_skb(hdev->sent_cmd);
hdev->sent_cmd = NULL; hdev->sent_cmd = NULL;
} }
...@@ -671,7 +684,7 @@ int hci_dev_reset(__u16 dev) ...@@ -671,7 +684,7 @@ int hci_dev_reset(__u16 dev)
hdev->flush(hdev); hdev->flush(hdev);
atomic_set(&hdev->cmd_cnt, 1); atomic_set(&hdev->cmd_cnt, 1);
hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0;
if (!test_bit(HCI_RAW, &hdev->flags)) if (!test_bit(HCI_RAW, &hdev->flags))
ret = __hci_request(hdev, hci_reset_req, 0, ret = __hci_request(hdev, hci_reset_req, 0,
...@@ -1054,6 +1067,16 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) ...@@ -1054,6 +1067,16 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
return 0; return 0;
} }
/* HCI command timer function */
static void hci_cmd_timer(unsigned long arg)
{
struct hci_dev *hdev = (void *) arg;
BT_ERR("%s command tx timeout", hdev->name);
atomic_set(&hdev->cmd_cnt, 1);
tasklet_schedule(&hdev->cmd_task);
}
/* Register HCI device */ /* Register HCI device */
int hci_register_dev(struct hci_dev *hdev) int hci_register_dev(struct hci_dev *hdev)
{ {
...@@ -1100,6 +1123,8 @@ int hci_register_dev(struct hci_dev *hdev) ...@@ -1100,6 +1123,8 @@ int hci_register_dev(struct hci_dev *hdev)
skb_queue_head_init(&hdev->cmd_q); skb_queue_head_init(&hdev->cmd_q);
skb_queue_head_init(&hdev->raw_q); skb_queue_head_init(&hdev->raw_q);
setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev);
for (i = 0; i < NUM_REASSEMBLY; i++) for (i = 0; i < NUM_REASSEMBLY; i++)
hdev->reassembly[i] = NULL; hdev->reassembly[i] = NULL;
...@@ -1187,6 +1212,8 @@ int hci_unregister_dev(struct hci_dev *hdev) ...@@ -1187,6 +1212,8 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_unregister_sysfs(hdev); hci_unregister_sysfs(hdev);
hci_del_off_timer(hdev);
destroy_workqueue(hdev->workqueue); destroy_workqueue(hdev->workqueue);
hci_dev_lock_bh(hdev); hci_dev_lock_bh(hdev);
...@@ -1672,8 +1699,25 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int ...@@ -1672,8 +1699,25 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
} }
if (conn) { if (conn) {
int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt); int cnt, q;
int q = cnt / num;
switch (conn->type) {
case ACL_LINK:
cnt = hdev->acl_cnt;
break;
case SCO_LINK:
case ESCO_LINK:
cnt = hdev->sco_cnt;
break;
case LE_LINK:
cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
break;
default:
cnt = 0;
BT_ERR("Unknown link type");
}
q = cnt / num;
*quote = q ? q : 1; *quote = q ? q : 1;
} else } else
*quote = 0; *quote = 0;
...@@ -1682,19 +1726,19 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int ...@@ -1682,19 +1726,19 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
return conn; return conn;
} }
static inline void hci_acl_tx_to(struct hci_dev *hdev) static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
{ {
struct hci_conn_hash *h = &hdev->conn_hash; struct hci_conn_hash *h = &hdev->conn_hash;
struct list_head *p; struct list_head *p;
struct hci_conn *c; struct hci_conn *c;
BT_ERR("%s ACL tx timeout", hdev->name); BT_ERR("%s link tx timeout", hdev->name);
/* Kill stalled connections */ /* Kill stalled connections */
list_for_each(p, &h->list) { list_for_each(p, &h->list) {
c = list_entry(p, struct hci_conn, list); c = list_entry(p, struct hci_conn, list);
if (c->type == ACL_LINK && c->sent) { if (c->type == type && c->sent) {
BT_ERR("%s killing stalled ACL connection %s", BT_ERR("%s killing stalled connection %s",
hdev->name, batostr(&c->dst)); hdev->name, batostr(&c->dst));
hci_acl_disconn(c, 0x13); hci_acl_disconn(c, 0x13);
} }
...@@ -1713,7 +1757,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev) ...@@ -1713,7 +1757,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
/* ACL tx timeout must be longer than maximum /* ACL tx timeout must be longer than maximum
* link supervision timeout (40.9 seconds) */ * link supervision timeout (40.9 seconds) */
if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + HZ * 45)) if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + HZ * 45))
hci_acl_tx_to(hdev); hci_link_tx_to(hdev, ACL_LINK);
} }
while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) { while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
...@@ -1772,6 +1816,40 @@ static inline void hci_sched_esco(struct hci_dev *hdev) ...@@ -1772,6 +1816,40 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
} }
} }
static inline void hci_sched_le(struct hci_dev *hdev)
{
struct hci_conn *conn;
struct sk_buff *skb;
int quote, cnt;
BT_DBG("%s", hdev->name);
if (!test_bit(HCI_RAW, &hdev->flags)) {
/* LE tx timeout must be longer than maximum
* link supervision timeout (40.9 seconds) */
if (!hdev->le_cnt && hdev->le_pkts &&
time_after(jiffies, hdev->le_last_tx + HZ * 45))
hci_link_tx_to(hdev, LE_LINK);
}
cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
while (cnt && (conn = hci_low_sent(hdev, LE_LINK, &quote))) {
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
BT_DBG("skb %p len %d", skb, skb->len);
hci_send_frame(skb);
hdev->le_last_tx = jiffies;
cnt--;
conn->sent++;
}
}
if (hdev->le_pkts)
hdev->le_cnt = cnt;
else
hdev->acl_cnt = cnt;
}
static void hci_tx_task(unsigned long arg) static void hci_tx_task(unsigned long arg)
{ {
struct hci_dev *hdev = (struct hci_dev *) arg; struct hci_dev *hdev = (struct hci_dev *) arg;
...@@ -1779,7 +1857,8 @@ static void hci_tx_task(unsigned long arg) ...@@ -1779,7 +1857,8 @@ static void hci_tx_task(unsigned long arg)
read_lock(&hci_task_lock); read_lock(&hci_task_lock);
BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt); BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt,
hdev->sco_cnt, hdev->le_cnt);
/* Schedule queues and send stuff to HCI driver */ /* Schedule queues and send stuff to HCI driver */
...@@ -1789,6 +1868,8 @@ static void hci_tx_task(unsigned long arg) ...@@ -1789,6 +1868,8 @@ static void hci_tx_task(unsigned long arg)
hci_sched_esco(hdev); hci_sched_esco(hdev);
hci_sched_le(hdev);
/* Send next queued raw (unknown type) packet */ /* Send next queued raw (unknown type) packet */
while ((skb = skb_dequeue(&hdev->raw_q))) while ((skb = skb_dequeue(&hdev->raw_q)))
hci_send_frame(skb); hci_send_frame(skb);
...@@ -1936,11 +2017,6 @@ static void hci_cmd_task(unsigned long arg) ...@@ -1936,11 +2017,6 @@ static void hci_cmd_task(unsigned long arg)
BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
if (!atomic_read(&hdev->cmd_cnt) && time_after(jiffies, hdev->cmd_last_tx + HZ)) {
BT_ERR("%s command tx timeout", hdev->name);
atomic_set(&hdev->cmd_cnt, 1);
}
/* Send queued commands */ /* Send queued commands */
if (atomic_read(&hdev->cmd_cnt)) { if (atomic_read(&hdev->cmd_cnt)) {
skb = skb_dequeue(&hdev->cmd_q); skb = skb_dequeue(&hdev->cmd_q);
...@@ -1953,7 +2029,8 @@ static void hci_cmd_task(unsigned long arg) ...@@ -1953,7 +2029,8 @@ static void hci_cmd_task(unsigned long arg)
if (hdev->sent_cmd) { if (hdev->sent_cmd) {
atomic_dec(&hdev->cmd_cnt); atomic_dec(&hdev->cmd_cnt);
hci_send_frame(skb); hci_send_frame(skb);
hdev->cmd_last_tx = jiffies; mod_timer(&hdev->cmd_timer,
jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT));
} else { } else {
skb_queue_head(&hdev->cmd_q, skb); skb_queue_head(&hdev->cmd_q, skb);
tasklet_schedule(&hdev->cmd_task); tasklet_schedule(&hdev->cmd_task);
......
...@@ -776,6 +776,25 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -776,6 +776,25 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
mgmt_pin_code_neg_reply_complete(hdev->id, &rp->bdaddr, mgmt_pin_code_neg_reply_complete(hdev->id, &rp->bdaddr,
rp->status); rp->status);
} }
static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_rp_le_read_buffer_size *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
if (rp->status)
return;
hdev->le_mtu = __le16_to_cpu(rp->le_mtu);
hdev->le_pkts = rp->le_max_pkt;
hdev->le_cnt = hdev->le_pkts;
BT_DBG("%s le mtu %d:%d", hdev->name, hdev->le_mtu, hdev->le_pkts);
hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status);
}
static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
{ {
...@@ -919,7 +938,7 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status) ...@@ -919,7 +938,7 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status)
} }
static int hci_outgoing_auth_needed(struct hci_dev *hdev, static int hci_outgoing_auth_needed(struct hci_dev *hdev,
struct hci_conn *conn) struct hci_conn *conn)
{ {
if (conn->state != BT_CONFIG || !conn->out) if (conn->state != BT_CONFIG || !conn->out)
return 0; return 0;
...@@ -1107,6 +1126,43 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status) ...@@ -1107,6 +1126,43 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
{
struct hci_cp_le_create_conn *cp;
struct hci_conn *conn;
BT_DBG("%s status 0x%x", hdev->name, status);
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN);
if (!cp)
return;
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->peer_addr),
conn);
if (status) {
if (conn && conn->state == BT_CONNECT) {
conn->state = BT_CLOSED;
hci_proto_connect_cfm(conn, status);
hci_conn_del(conn);
}
} else {
if (!conn) {
conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
if (conn)
conn->out = 1;
else
BT_ERR("No memory for new connection");
}
}
hci_dev_unlock(hdev);
}
static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
__u8 status = *((__u8 *) skb->data); __u8 status = *((__u8 *) skb->data);
...@@ -1237,7 +1293,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk ...@@ -1237,7 +1293,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type); mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
if ((mask & HCI_LM_ACCEPT) && !hci_blacklist_lookup(hdev, &ev->bdaddr)) { if ((mask & HCI_LM_ACCEPT) &&
!hci_blacklist_lookup(hdev, &ev->bdaddr)) {
/* Connection accepted */ /* Connection accepted */
struct inquiry_entry *ie; struct inquiry_entry *ie;
struct hci_conn *conn; struct hci_conn *conn;
...@@ -1667,11 +1724,18 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk ...@@ -1667,11 +1724,18 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_pin_code_neg_reply(hdev, skb); hci_cc_pin_code_neg_reply(hdev, skb);
break; break;
case HCI_OP_LE_READ_BUFFER_SIZE:
hci_cc_le_read_buffer_size(hdev, skb);
break;
default: default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode); BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break; break;
} }
if (ev->opcode != HCI_OP_NOP)
del_timer(&hdev->cmd_timer);
if (ev->ncmd) { if (ev->ncmd) {
atomic_set(&hdev->cmd_cnt, 1); atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q)) if (!skb_queue_empty(&hdev->cmd_q))
...@@ -1738,11 +1802,18 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -1738,11 +1802,18 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
mgmt_disconnect_failed(hdev->id); mgmt_disconnect_failed(hdev->id);
break; break;
case HCI_OP_LE_CREATE_CONN:
hci_cs_le_create_conn(hdev, ev->status);
break;
default: default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode); BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break; break;
} }
if (ev->opcode != HCI_OP_NOP)
del_timer(&hdev->cmd_timer);
if (ev->ncmd) { if (ev->ncmd) {
atomic_set(&hdev->cmd_cnt, 1); atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q)) if (!skb_queue_empty(&hdev->cmd_q))
...@@ -1808,6 +1879,16 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s ...@@ -1808,6 +1879,16 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
hdev->acl_cnt += count; hdev->acl_cnt += count;
if (hdev->acl_cnt > hdev->acl_pkts) if (hdev->acl_cnt > hdev->acl_pkts)
hdev->acl_cnt = hdev->acl_pkts; hdev->acl_cnt = hdev->acl_pkts;
} else if (conn->type == LE_LINK) {
if (hdev->le_pkts) {
hdev->le_cnt += count;
if (hdev->le_cnt > hdev->le_pkts)
hdev->le_cnt = hdev->le_pkts;
} else {
hdev->acl_cnt += count;
if (hdev->acl_cnt > hdev->acl_pkts)
hdev->acl_cnt = hdev->acl_pkts;
}
} else { } else {
hdev->sco_cnt += count; hdev->sco_cnt += count;
if (hdev->sco_cnt > hdev->sco_pkts) if (hdev->sco_cnt > hdev->sco_pkts)
...@@ -2021,7 +2102,8 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct ...@@ -2021,7 +2102,8 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
hci_dev_lock(hdev); hci_dev_lock(hdev);
if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) { if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
struct inquiry_info_with_rssi_and_pscan_mode *info = (void *) (skb->data + 1); struct inquiry_info_with_rssi_and_pscan_mode *info;
info = (void *) (skb->data + 1);
for (; num_rsp; num_rsp--) { for (; num_rsp; num_rsp--) {
bacpy(&data.bdaddr, &info->bdaddr); bacpy(&data.bdaddr, &info->bdaddr);
...@@ -2162,17 +2244,8 @@ static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buf ...@@ -2162,17 +2244,8 @@ static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buf
static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_sniff_subrate *ev = (void *) skb->data; struct hci_ev_sniff_subrate *ev = (void *) skb->data;
struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status); BT_DBG("%s status %d", hdev->name, ev->status);
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) {
}
hci_dev_unlock(hdev);
} }
static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -2190,12 +2263,12 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct ...@@ -2190,12 +2263,12 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
for (; num_rsp; num_rsp--) { for (; num_rsp; num_rsp--) {
bacpy(&data.bdaddr, &info->bdaddr); bacpy(&data.bdaddr, &info->bdaddr);
data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_rep_mode = info->pscan_rep_mode;
data.pscan_period_mode = info->pscan_period_mode; data.pscan_period_mode = info->pscan_period_mode;
data.pscan_mode = 0x00; data.pscan_mode = 0x00;
memcpy(data.dev_class, info->dev_class, 3); memcpy(data.dev_class, info->dev_class, 3);
data.clock_offset = info->clock_offset; data.clock_offset = info->clock_offset;
data.rssi = info->rssi; data.rssi = info->rssi;
data.ssp_mode = 0x01; data.ssp_mode = 0x01;
info++; info++;
hci_inquiry_cache_update(hdev, &data); hci_inquiry_cache_update(hdev, &data);
...@@ -2321,6 +2394,60 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_ ...@@ -2321,6 +2394,60 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_le_conn_complete *ev = (void *) skb->data;
struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status);
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
if (!conn) {
conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
if (!conn) {
BT_ERR("No memory for new connection");
hci_dev_unlock(hdev);
return;
}
}
if (ev->status) {
hci_proto_connect_cfm(conn, ev->status);
conn->state = BT_CLOSED;
hci_conn_del(conn);
goto unlock;
}
conn->handle = __le16_to_cpu(ev->handle);
conn->state = BT_CONNECTED;
hci_conn_hold_device(conn);
hci_conn_add_sysfs(conn);
hci_proto_connect_cfm(conn, ev->status);
unlock:
hci_dev_unlock(hdev);
}
static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_le_meta *le_ev = (void *) skb->data;
skb_pull(skb, sizeof(*le_ev));
switch (le_ev->subevent) {
case HCI_EV_LE_CONN_COMPLETE:
hci_le_conn_complete_evt(hdev, skb);
break;
default:
break;
}
}
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_event_hdr *hdr = (void *) skb->data; struct hci_event_hdr *hdr = (void *) skb->data;
...@@ -2461,6 +2588,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2461,6 +2588,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_remote_host_features_evt(hdev, skb); hci_remote_host_features_evt(hdev, skb);
break; break;
case HCI_EV_LE_META:
hci_le_meta_evt(hdev, skb);
break;
default: default:
BT_DBG("%s event 0x%x", hdev->name, event); BT_DBG("%s event 0x%x", hdev->name, event);
break; break;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
static struct class *bt_class; static struct class *bt_class;
struct dentry *bt_debugfs = NULL; struct dentry *bt_debugfs;
EXPORT_SYMBOL_GPL(bt_debugfs); EXPORT_SYMBOL_GPL(bt_debugfs);
static inline char *link_typetostr(int type) static inline char *link_typetostr(int type)
...@@ -51,8 +51,8 @@ static ssize_t show_link_features(struct device *dev, struct device_attribute *a ...@@ -51,8 +51,8 @@ static ssize_t show_link_features(struct device *dev, struct device_attribute *a
conn->features[6], conn->features[7]); conn->features[6], conn->features[7]);
} }
#define LINK_ATTR(_name,_mode,_show,_store) \ #define LINK_ATTR(_name, _mode, _show, _store) \
struct device_attribute link_attr_##_name = __ATTR(_name,_mode,_show,_store) struct device_attribute link_attr_##_name = __ATTR(_name, _mode, _show, _store)
static LINK_ATTR(type, S_IRUGO, show_link_type, NULL); static LINK_ATTR(type, S_IRUGO, show_link_type, NULL);
static LINK_ATTR(address, S_IRUGO, show_link_address, NULL); static LINK_ATTR(address, S_IRUGO, show_link_address, NULL);
......
...@@ -1019,8 +1019,6 @@ static int __init hidp_init(void) ...@@ -1019,8 +1019,6 @@ static int __init hidp_init(void)
{ {
int ret; int ret;
l2cap_load();
BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION); BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
ret = hid_register_driver(&hidp_driver); ret = hid_register_driver(&hidp_driver);
......
...@@ -55,8 +55,6 @@ ...@@ -55,8 +55,6 @@
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h> #include <net/bluetooth/l2cap.h>
#define VERSION "2.15"
int disable_ertm; int disable_ertm;
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
...@@ -183,8 +181,16 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so ...@@ -183,8 +181,16 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
l2cap_pi(sk)->conn = conn; l2cap_pi(sk)->conn = conn;
if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) { if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) {
/* Alloc CID for connection-oriented socket */ if (conn->hcon->type == LE_LINK) {
l2cap_pi(sk)->scid = l2cap_alloc_cid(l); /* LE connection */
l2cap_pi(sk)->omtu = L2CAP_LE_DEFAULT_MTU;
l2cap_pi(sk)->scid = L2CAP_CID_LE_DATA;
l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA;
} else {
/* Alloc CID for connection-oriented socket */
l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
}
} else if (sk->sk_type == SOCK_DGRAM) { } else if (sk->sk_type == SOCK_DGRAM) {
/* Connectionless socket */ /* Connectionless socket */
l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS; l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS;
...@@ -583,6 +589,82 @@ static void l2cap_conn_start(struct l2cap_conn *conn) ...@@ -583,6 +589,82 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
} }
} }
/* Find socket with cid and source bdaddr.
* Returns closest match, locked.
*/
static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src)
{
struct sock *s, *sk = NULL, *sk1 = NULL;
struct hlist_node *node;
read_lock(&l2cap_sk_list.lock);
sk_for_each(sk, node, &l2cap_sk_list.head) {
if (state && sk->sk_state != state)
continue;
if (l2cap_pi(sk)->scid == cid) {
/* Exact match. */
if (!bacmp(&bt_sk(sk)->src, src))
break;
/* Closest match */
if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
sk1 = sk;
}
}
s = node ? sk : sk1;
if (s)
bh_lock_sock(s);
read_unlock(&l2cap_sk_list.lock);
return s;
}
static void l2cap_le_conn_ready(struct l2cap_conn *conn)
{
struct l2cap_chan_list *list = &conn->chan_list;
struct sock *parent, *uninitialized_var(sk);
BT_DBG("");
/* Check if we have socket listening on cid */
parent = l2cap_get_sock_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
conn->src);
if (!parent)
return;
/* Check for backlog size */
if (sk_acceptq_is_full(parent)) {
BT_DBG("backlog full %d", parent->sk_ack_backlog);
goto clean;
}
sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
if (!sk)
goto clean;
write_lock_bh(&list->lock);
hci_conn_hold(conn->hcon);
l2cap_sock_init(sk, parent);
bacpy(&bt_sk(sk)->src, conn->src);
bacpy(&bt_sk(sk)->dst, conn->dst);
__l2cap_chan_add(conn, sk, parent);
l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
sk->sk_state = BT_CONNECTED;
parent->sk_data_ready(parent, 0);
write_unlock_bh(&list->lock);
clean:
bh_unlock_sock(parent);
}
static void l2cap_conn_ready(struct l2cap_conn *conn) static void l2cap_conn_ready(struct l2cap_conn *conn)
{ {
struct l2cap_chan_list *l = &conn->chan_list; struct l2cap_chan_list *l = &conn->chan_list;
...@@ -590,11 +672,20 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) ...@@ -590,11 +672,20 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
BT_DBG("conn %p", conn); BT_DBG("conn %p", conn);
if (!conn->hcon->out && conn->hcon->type == LE_LINK)
l2cap_le_conn_ready(conn);
read_lock(&l->lock); read_lock(&l->lock);
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
bh_lock_sock(sk); bh_lock_sock(sk);
if (conn->hcon->type == LE_LINK) {
l2cap_sock_clear_timer(sk);
sk->sk_state = BT_CONNECTED;
sk->sk_state_change(sk);
}
if (sk->sk_type != SOCK_SEQPACKET && if (sk->sk_type != SOCK_SEQPACKET &&
sk->sk_type != SOCK_STREAM) { sk->sk_type != SOCK_STREAM) {
l2cap_sock_clear_timer(sk); l2cap_sock_clear_timer(sk);
...@@ -653,7 +744,11 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) ...@@ -653,7 +744,11 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
BT_DBG("hcon %p conn %p", hcon, conn); BT_DBG("hcon %p conn %p", hcon, conn);
conn->mtu = hcon->hdev->acl_mtu; if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
conn->mtu = hcon->hdev->le_mtu;
else
conn->mtu = hcon->hdev->acl_mtu;
conn->src = &hcon->hdev->bdaddr; conn->src = &hcon->hdev->bdaddr;
conn->dst = &hcon->dst; conn->dst = &hcon->dst;
...@@ -662,7 +757,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) ...@@ -662,7 +757,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
spin_lock_init(&conn->lock); spin_lock_init(&conn->lock);
rwlock_init(&conn->chan_list.lock); rwlock_init(&conn->chan_list.lock);
setup_timer(&conn->info_timer, l2cap_info_timeout, if (hcon->type != LE_LINK)
setup_timer(&conn->info_timer, l2cap_info_timeout,
(unsigned long) conn); (unsigned long) conn);
conn->disc_reason = 0x13; conn->disc_reason = 0x13;
...@@ -760,8 +856,13 @@ int l2cap_do_connect(struct sock *sk) ...@@ -760,8 +856,13 @@ int l2cap_do_connect(struct sock *sk)
auth_type = l2cap_get_auth_type(sk); auth_type = l2cap_get_auth_type(sk);
hcon = hci_connect(hdev, ACL_LINK, dst, if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA)
hcon = hci_connect(hdev, LE_LINK, dst,
l2cap_pi(sk)->sec_level, auth_type); l2cap_pi(sk)->sec_level, auth_type);
else
hcon = hci_connect(hdev, ACL_LINK, dst,
l2cap_pi(sk)->sec_level, auth_type);
if (!hcon) if (!hcon)
goto done; goto done;
...@@ -1327,7 +1428,11 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, ...@@ -1327,7 +1428,11 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen); lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
if (conn->hcon->type == LE_LINK)
lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
else
lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE); cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
cmd->code = code; cmd->code = code;
...@@ -1566,10 +1671,6 @@ int l2cap_build_conf_req(struct sock *sk, void *data) ...@@ -1566,10 +1671,6 @@ int l2cap_build_conf_req(struct sock *sk, void *data)
break; break;
} }
/* FIXME: Need actual value of the flush timeout */
//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
// l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
req->dcid = cpu_to_le16(pi->dcid); req->dcid = cpu_to_le16(pi->dcid);
req->flags = cpu_to_le16(0); req->flags = cpu_to_le16(0);
...@@ -2396,12 +2497,153 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm ...@@ -2396,12 +2497,153 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
return 0; return 0;
} }
static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
u16 to_multiplier)
{
u16 max_latency;
if (min > max || min < 6 || max > 3200)
return -EINVAL;
if (to_multiplier < 10 || to_multiplier > 3200)
return -EINVAL;
if (max >= to_multiplier * 8)
return -EINVAL;
max_latency = (to_multiplier * 8 / max) - 1;
if (latency > 499 || latency > max_latency)
return -EINVAL;
return 0;
}
static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u8 *data)
{
struct hci_conn *hcon = conn->hcon;
struct l2cap_conn_param_update_req *req;
struct l2cap_conn_param_update_rsp rsp;
u16 min, max, latency, to_multiplier, cmd_len;
int err;
if (!(hcon->link_mode & HCI_LM_MASTER))
return -EINVAL;
cmd_len = __le16_to_cpu(cmd->len);
if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
return -EPROTO;
req = (struct l2cap_conn_param_update_req *) data;
min = __le16_to_cpu(req->min);
max = __le16_to_cpu(req->max);
latency = __le16_to_cpu(req->latency);
to_multiplier = __le16_to_cpu(req->to_multiplier);
BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
min, max, latency, to_multiplier);
memset(&rsp, 0, sizeof(rsp));
err = l2cap_check_conn_param(min, max, latency, to_multiplier);
if (err)
rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
else
rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
sizeof(rsp), &rsp);
if (!err)
hci_le_conn_update(hcon, min, max, latency, to_multiplier);
return 0;
}
static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
{
int err = 0;
switch (cmd->code) {
case L2CAP_COMMAND_REJ:
l2cap_command_rej(conn, cmd, data);
break;
case L2CAP_CONN_REQ:
err = l2cap_connect_req(conn, cmd, data);
break;
case L2CAP_CONN_RSP:
err = l2cap_connect_rsp(conn, cmd, data);
break;
case L2CAP_CONF_REQ:
err = l2cap_config_req(conn, cmd, cmd_len, data);
break;
case L2CAP_CONF_RSP:
err = l2cap_config_rsp(conn, cmd, data);
break;
case L2CAP_DISCONN_REQ:
err = l2cap_disconnect_req(conn, cmd, data);
break;
case L2CAP_DISCONN_RSP:
err = l2cap_disconnect_rsp(conn, cmd, data);
break;
case L2CAP_ECHO_REQ:
l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
break;
case L2CAP_ECHO_RSP:
break;
case L2CAP_INFO_REQ:
err = l2cap_information_req(conn, cmd, data);
break;
case L2CAP_INFO_RSP:
err = l2cap_information_rsp(conn, cmd, data);
break;
default:
BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
err = -EINVAL;
break;
}
return err;
}
static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u8 *data)
{
switch (cmd->code) {
case L2CAP_COMMAND_REJ:
return 0;
case L2CAP_CONN_PARAM_UPDATE_REQ:
return l2cap_conn_param_update_req(conn, cmd, data);
case L2CAP_CONN_PARAM_UPDATE_RSP:
return 0;
default:
BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
return -EINVAL;
}
}
static inline void l2cap_sig_channel(struct l2cap_conn *conn,
struct sk_buff *skb)
{ {
u8 *data = skb->data; u8 *data = skb->data;
int len = skb->len; int len = skb->len;
struct l2cap_cmd_hdr cmd; struct l2cap_cmd_hdr cmd;
int err = 0; int err;
l2cap_raw_recv(conn, skb); l2cap_raw_recv(conn, skb);
...@@ -2420,55 +2662,10 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk ...@@ -2420,55 +2662,10 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk
break; break;
} }
switch (cmd.code) { if (conn->hcon->type == LE_LINK)
case L2CAP_COMMAND_REJ: err = l2cap_le_sig_cmd(conn, &cmd, data);
l2cap_command_rej(conn, &cmd, data); else
break; err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
case L2CAP_CONN_REQ:
err = l2cap_connect_req(conn, &cmd, data);
break;
case L2CAP_CONN_RSP:
err = l2cap_connect_rsp(conn, &cmd, data);
break;
case L2CAP_CONF_REQ:
err = l2cap_config_req(conn, &cmd, cmd_len, data);
break;
case L2CAP_CONF_RSP:
err = l2cap_config_rsp(conn, &cmd, data);
break;
case L2CAP_DISCONN_REQ:
err = l2cap_disconnect_req(conn, &cmd, data);
break;
case L2CAP_DISCONN_RSP:
err = l2cap_disconnect_rsp(conn, &cmd, data);
break;
case L2CAP_ECHO_REQ:
l2cap_send_cmd(conn, cmd.ident, L2CAP_ECHO_RSP, cmd_len, data);
break;
case L2CAP_ECHO_RSP:
break;
case L2CAP_INFO_REQ:
err = l2cap_information_req(conn, &cmd, data);
break;
case L2CAP_INFO_RSP:
err = l2cap_information_rsp(conn, &cmd, data);
break;
default:
BT_ERR("Unknown signaling command 0x%2.2x", cmd.code);
err = -EINVAL;
break;
}
if (err) { if (err) {
struct l2cap_cmd_rej rej; struct l2cap_cmd_rej rej;
...@@ -3465,6 +3662,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -3465,6 +3662,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
BT_DBG("len %d, cid 0x%4.4x", len, cid); BT_DBG("len %d, cid 0x%4.4x", len, cid);
switch (cid) { switch (cid) {
case L2CAP_CID_LE_SIGNALING:
case L2CAP_CID_SIGNALING: case L2CAP_CID_SIGNALING:
l2cap_sig_channel(conn, skb); l2cap_sig_channel(conn, skb);
break; break;
...@@ -3522,7 +3720,7 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status) ...@@ -3522,7 +3720,7 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
if (hcon->type != ACL_LINK) if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
return -EINVAL; return -EINVAL;
if (!status) { if (!status) {
...@@ -3551,7 +3749,7 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) ...@@ -3551,7 +3749,7 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
{ {
BT_DBG("hcon %p reason %d", hcon, reason); BT_DBG("hcon %p reason %d", hcon, reason);
if (hcon->type != ACL_LINK) if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
return -EINVAL; return -EINVAL;
l2cap_conn_del(hcon, bt_err(reason)); l2cap_conn_del(hcon, bt_err(reason));
...@@ -3768,12 +3966,13 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p) ...@@ -3768,12 +3966,13 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
sk_for_each(sk, node, &l2cap_sk_list.head) { sk_for_each(sk, node, &l2cap_sk_list.head) {
struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_pinfo *pi = l2cap_pi(sk);
seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n", seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->src),
batostr(&bt_sk(sk)->dst), batostr(&bt_sk(sk)->dst),
sk->sk_state, __le16_to_cpu(pi->psm), sk->sk_state, __le16_to_cpu(pi->psm),
pi->scid, pi->dcid, pi->scid, pi->dcid,
pi->imtu, pi->omtu, pi->sec_level); pi->imtu, pi->omtu, pi->sec_level,
pi->mode);
} }
read_unlock_bh(&l2cap_sk_list.lock); read_unlock_bh(&l2cap_sk_list.lock);
...@@ -3806,7 +4005,7 @@ static struct hci_proto l2cap_hci_proto = { ...@@ -3806,7 +4005,7 @@ static struct hci_proto l2cap_hci_proto = {
.recv_acldata = l2cap_recv_acldata .recv_acldata = l2cap_recv_acldata
}; };
static int __init l2cap_init(void) int __init l2cap_init(void)
{ {
int err; int err;
...@@ -3834,7 +4033,6 @@ static int __init l2cap_init(void) ...@@ -3834,7 +4033,6 @@ static int __init l2cap_init(void)
BT_ERR("Failed to create L2CAP debug file"); BT_ERR("Failed to create L2CAP debug file");
} }
BT_INFO("L2CAP ver %s", VERSION);
BT_INFO("L2CAP socket layer initialized"); BT_INFO("L2CAP socket layer initialized");
return 0; return 0;
...@@ -3845,7 +4043,7 @@ static int __init l2cap_init(void) ...@@ -3845,7 +4043,7 @@ static int __init l2cap_init(void)
return err; return err;
} }
static void __exit l2cap_exit(void) void l2cap_exit(void)
{ {
debugfs_remove(l2cap_debugfs); debugfs_remove(l2cap_debugfs);
...@@ -3858,22 +4056,5 @@ static void __exit l2cap_exit(void) ...@@ -3858,22 +4056,5 @@ static void __exit l2cap_exit(void)
l2cap_cleanup_sockets(); l2cap_cleanup_sockets();
} }
void l2cap_load(void)
{
/* Dummy function to trigger automatic L2CAP module loading by
* other modules that use L2CAP sockets but don't use any other
* symbols from it. */
}
EXPORT_SYMBOL(l2cap_load);
module_init(l2cap_init);
module_exit(l2cap_exit);
module_param(disable_ertm, bool, 0644); module_param(disable_ertm, bool, 0644);
MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode"); MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
MODULE_ALIAS("bt-proto-0");
...@@ -103,7 +103,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) ...@@ -103,7 +103,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
len = min_t(unsigned int, sizeof(la), alen); len = min_t(unsigned int, sizeof(la), alen);
memcpy(&la, addr, len); memcpy(&la, addr, len);
if (la.l2_cid) if (la.l2_cid && la.l2_psm)
return -EINVAL; return -EINVAL;
lock_sock(sk); lock_sock(sk);
...@@ -145,6 +145,9 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) ...@@ -145,6 +145,9 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
} }
if (la.l2_cid)
l2cap_pi(sk)->scid = la.l2_cid;
write_unlock_bh(&l2cap_sk_list.lock); write_unlock_bh(&l2cap_sk_list.lock);
done: done:
...@@ -168,13 +171,13 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al ...@@ -168,13 +171,13 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
len = min_t(unsigned int, sizeof(la), alen); len = min_t(unsigned int, sizeof(la), alen);
memcpy(&la, addr, len); memcpy(&la, addr, len);
if (la.l2_cid) if (la.l2_cid && la.l2_psm)
return -EINVAL; return -EINVAL;
lock_sock(sk); lock_sock(sk);
if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM)
&& !la.l2_psm) { && !(la.l2_psm || la.l2_cid)) {
err = -EINVAL; err = -EINVAL;
goto done; goto done;
} }
...@@ -216,7 +219,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al ...@@ -216,7 +219,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
/* PSM must be odd and lsb of upper byte must be 0 */ /* PSM must be odd and lsb of upper byte must be 0 */
if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 && if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 &&
sk->sk_type != SOCK_RAW) { sk->sk_type != SOCK_RAW && !la.l2_cid) {
err = -EINVAL; err = -EINVAL;
goto done; goto done;
} }
...@@ -224,6 +227,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al ...@@ -224,6 +227,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
/* Set destination address and psm */ /* Set destination address and psm */
bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr); bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
l2cap_pi(sk)->psm = la.l2_psm; l2cap_pi(sk)->psm = la.l2_psm;
l2cap_pi(sk)->dcid = la.l2_cid;
err = l2cap_do_connect(sk); err = l2cap_do_connect(sk);
if (err) if (err)
...@@ -265,7 +269,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) ...@@ -265,7 +269,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
goto done; goto done;
} }
if (!l2cap_pi(sk)->psm) { if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->dcid) {
bdaddr_t *src = &bt_sk(sk)->src; bdaddr_t *src = &bt_sk(sk)->src;
u16 psm; u16 psm;
...@@ -392,6 +396,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us ...@@ -392,6 +396,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
switch (optname) { switch (optname) {
case L2CAP_OPTIONS: case L2CAP_OPTIONS:
memset(&opts, 0, sizeof(opts));
opts.imtu = l2cap_pi(sk)->imtu; opts.imtu = l2cap_pi(sk)->imtu;
opts.omtu = l2cap_pi(sk)->omtu; opts.omtu = l2cap_pi(sk)->omtu;
opts.flush_to = l2cap_pi(sk)->flush_to; opts.flush_to = l2cap_pi(sk)->flush_to;
...@@ -880,6 +885,8 @@ static void l2cap_sock_cleanup_listen(struct sock *parent) ...@@ -880,6 +885,8 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
void __l2cap_sock_close(struct sock *sk, int reason) void __l2cap_sock_close(struct sock *sk, int reason)
{ {
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket); BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
switch (sk->sk_state) { switch (sk->sk_state) {
...@@ -889,10 +896,9 @@ void __l2cap_sock_close(struct sock *sk, int reason) ...@@ -889,10 +896,9 @@ void __l2cap_sock_close(struct sock *sk, int reason)
case BT_CONNECTED: case BT_CONNECTED:
case BT_CONFIG: case BT_CONFIG:
if (sk->sk_type == SOCK_SEQPACKET || if ((sk->sk_type == SOCK_SEQPACKET ||
sk->sk_type == SOCK_STREAM) { sk->sk_type == SOCK_STREAM) &&
struct l2cap_conn *conn = l2cap_pi(sk)->conn; conn->hcon->type == ACL_LINK) {
l2cap_sock_set_timer(sk, sk->sk_sndtimeo); l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
l2cap_send_disconn_req(conn, sk, reason); l2cap_send_disconn_req(conn, sk, reason);
} else } else
...@@ -900,9 +906,9 @@ void __l2cap_sock_close(struct sock *sk, int reason) ...@@ -900,9 +906,9 @@ void __l2cap_sock_close(struct sock *sk, int reason)
break; break;
case BT_CONNECT2: case BT_CONNECT2:
if (sk->sk_type == SOCK_SEQPACKET || if ((sk->sk_type == SOCK_SEQPACKET ||
sk->sk_type == SOCK_STREAM) { sk->sk_type == SOCK_STREAM) &&
struct l2cap_conn *conn = l2cap_pi(sk)->conn; conn->hcon->type == ACL_LINK) {
struct l2cap_conn_rsp rsp; struct l2cap_conn_rsp rsp;
__u16 result; __u16 result;
...@@ -1121,30 +1127,30 @@ static const struct net_proto_family l2cap_sock_family_ops = { ...@@ -1121,30 +1127,30 @@ static const struct net_proto_family l2cap_sock_family_ops = {
int __init l2cap_init_sockets(void) int __init l2cap_init_sockets(void)
{ {
int err; int err;
err = proto_register(&l2cap_proto, 0); err = proto_register(&l2cap_proto, 0);
if (err < 0) if (err < 0)
return err; return err;
err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops); err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
if (err < 0) if (err < 0)
goto error; goto error;
BT_INFO("L2CAP socket layer initialized"); BT_INFO("L2CAP socket layer initialized");
return 0; return 0;
error: error:
BT_ERR("L2CAP socket registration failed"); BT_ERR("L2CAP socket registration failed");
proto_unregister(&l2cap_proto); proto_unregister(&l2cap_proto);
return err; return err;
} }
void l2cap_cleanup_sockets(void) void l2cap_cleanup_sockets(void)
{ {
if (bt_sock_unregister(BTPROTO_L2CAP) < 0) if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
BT_ERR("L2CAP socket unregistration failed"); BT_ERR("L2CAP socket unregistration failed");
proto_unregister(&l2cap_proto); proto_unregister(&l2cap_proto);
} }
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
/* Bluetooth HCI Management interface */ /* Bluetooth HCI Management interface */
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
......
...@@ -2154,8 +2154,6 @@ static int __init rfcomm_init(void) ...@@ -2154,8 +2154,6 @@ static int __init rfcomm_init(void)
{ {
int err; int err;
l2cap_load();
hci_register_cb(&rfcomm_cb); hci_register_cb(&rfcomm_cb);
rfcomm_thread = kthread_run(rfcomm_run, NULL, "krfcommd"); rfcomm_thread = kthread_run(rfcomm_run, NULL, "krfcommd");
......
...@@ -50,8 +50,6 @@ ...@@ -50,8 +50,6 @@
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#include <net/bluetooth/sco.h> #include <net/bluetooth/sco.h>
#define VERSION "0.6"
static int disable_esco; static int disable_esco;
static const struct proto_ops sco_sock_ops; static const struct proto_ops sco_sock_ops;
...@@ -703,6 +701,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user ...@@ -703,6 +701,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user
break; break;
} }
memset(&cinfo, 0, sizeof(cinfo));
cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle; cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3); memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
...@@ -1023,7 +1022,7 @@ static struct hci_proto sco_hci_proto = { ...@@ -1023,7 +1022,7 @@ static struct hci_proto sco_hci_proto = {
.recv_scodata = sco_recv_scodata .recv_scodata = sco_recv_scodata
}; };
static int __init sco_init(void) int __init sco_init(void)
{ {
int err; int err;
...@@ -1051,7 +1050,6 @@ static int __init sco_init(void) ...@@ -1051,7 +1050,6 @@ static int __init sco_init(void)
BT_ERR("Failed to create SCO debug file"); BT_ERR("Failed to create SCO debug file");
} }
BT_INFO("SCO (Voice Link) ver %s", VERSION);
BT_INFO("SCO socket layer initialized"); BT_INFO("SCO socket layer initialized");
return 0; return 0;
...@@ -1061,7 +1059,7 @@ static int __init sco_init(void) ...@@ -1061,7 +1059,7 @@ static int __init sco_init(void)
return err; return err;
} }
static void __exit sco_exit(void) void __exit sco_exit(void)
{ {
debugfs_remove(sco_debugfs); debugfs_remove(sco_debugfs);
...@@ -1074,14 +1072,5 @@ static void __exit sco_exit(void) ...@@ -1074,14 +1072,5 @@ static void __exit sco_exit(void)
proto_unregister(&sco_proto); proto_unregister(&sco_proto);
} }
module_init(sco_init);
module_exit(sco_exit);
module_param(disable_esco, bool, 0644); module_param(disable_esco, bool, 0644);
MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation"); MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation");
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
MODULE_ALIAS("bt-proto-2");
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册