Commit f3b3e36f authored by John W. Linville's avatar John W. Linville
parents b0006e69 db940cb0
...@@ -71,6 +71,9 @@ static struct usb_device_id btusb_table[] = { ...@@ -71,6 +71,9 @@ static struct usb_device_id btusb_table[] = {
/* Apple MacBookAir3,1, MacBookAir3,2 */ /* Apple MacBookAir3,1, MacBookAir3,2 */
{ USB_DEVICE(0x05ac, 0x821b) }, { USB_DEVICE(0x05ac, 0x821b) },
/* Apple MacBookPro8,2 */
{ USB_DEVICE(0x05ac, 0x821a) },
/* AVM BlueFRITZ! USB v2.0 */ /* AVM BlueFRITZ! USB v2.0 */
{ USB_DEVICE(0x057c, 0x3800) }, { USB_DEVICE(0x057c, 0x3800) },
...@@ -690,7 +693,8 @@ static int btusb_send_frame(struct sk_buff *skb) ...@@ -690,7 +693,8 @@ static int btusb_send_frame(struct sk_buff *skb)
break; break;
case HCI_ACLDATA_PKT: case HCI_ACLDATA_PKT:
if (!data->bulk_tx_ep || hdev->conn_hash.acl_num < 1) if (!data->bulk_tx_ep || (hdev->conn_hash.acl_num < 1 &&
hdev->conn_hash.le_num < 1))
return -ENODEV; return -ENODEV;
urb = usb_alloc_urb(0, GFP_ATOMIC); urb = usb_alloc_urb(0, GFP_ATOMIC);
......
...@@ -84,6 +84,8 @@ enum { ...@@ -84,6 +84,8 @@ enum {
HCI_SERVICE_CACHE, HCI_SERVICE_CACHE,
HCI_LINK_KEYS, HCI_LINK_KEYS,
HCI_DEBUG_KEYS, HCI_DEBUG_KEYS,
HCI_RESET,
}; };
/* HCI ioctl defines */ /* HCI ioctl defines */
...@@ -426,6 +428,18 @@ struct hci_rp_user_confirm_reply { ...@@ -426,6 +428,18 @@ struct hci_rp_user_confirm_reply {
#define HCI_OP_USER_CONFIRM_NEG_REPLY 0x042d #define HCI_OP_USER_CONFIRM_NEG_REPLY 0x042d
#define HCI_OP_REMOTE_OOB_DATA_REPLY 0x0430
struct hci_cp_remote_oob_data_reply {
bdaddr_t bdaddr;
__u8 hash[16];
__u8 randomizer[16];
} __packed;
#define HCI_OP_REMOTE_OOB_DATA_NEG_REPLY 0x0433
struct hci_cp_remote_oob_data_neg_reply {
bdaddr_t bdaddr;
} __packed;
#define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434 #define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434
struct hci_cp_io_capability_neg_reply { struct hci_cp_io_capability_neg_reply {
bdaddr_t bdaddr; bdaddr_t bdaddr;
...@@ -535,15 +549,17 @@ struct hci_cp_delete_stored_link_key { ...@@ -535,15 +549,17 @@ struct hci_cp_delete_stored_link_key {
__u8 delete_all; __u8 delete_all;
} __packed; } __packed;
#define HCI_MAX_NAME_LENGTH 248
#define HCI_OP_WRITE_LOCAL_NAME 0x0c13 #define HCI_OP_WRITE_LOCAL_NAME 0x0c13
struct hci_cp_write_local_name { struct hci_cp_write_local_name {
__u8 name[248]; __u8 name[HCI_MAX_NAME_LENGTH];
} __packed; } __packed;
#define HCI_OP_READ_LOCAL_NAME 0x0c14 #define HCI_OP_READ_LOCAL_NAME 0x0c14
struct hci_rp_read_local_name { struct hci_rp_read_local_name {
__u8 status; __u8 status;
__u8 name[248]; __u8 name[HCI_MAX_NAME_LENGTH];
} __packed; } __packed;
#define HCI_OP_WRITE_CA_TIMEOUT 0x0c16 #define HCI_OP_WRITE_CA_TIMEOUT 0x0c16
...@@ -600,6 +616,14 @@ struct hci_cp_host_buffer_size { ...@@ -600,6 +616,14 @@ struct hci_cp_host_buffer_size {
#define HCI_OP_WRITE_INQUIRY_MODE 0x0c45 #define HCI_OP_WRITE_INQUIRY_MODE 0x0c45
#define HCI_MAX_EIR_LENGTH 240
#define HCI_OP_WRITE_EIR 0x0c52
struct hci_cp_write_eir {
uint8_t fec;
uint8_t data[HCI_MAX_EIR_LENGTH];
} __packed;
#define HCI_OP_READ_SSP_MODE 0x0c55 #define HCI_OP_READ_SSP_MODE 0x0c55
struct hci_rp_read_ssp_mode { struct hci_rp_read_ssp_mode {
__u8 status; __u8 status;
...@@ -611,6 +635,13 @@ struct hci_cp_write_ssp_mode { ...@@ -611,6 +635,13 @@ struct hci_cp_write_ssp_mode {
__u8 mode; __u8 mode;
} __packed; } __packed;
#define HCI_OP_READ_LOCAL_OOB_DATA 0x0c57
struct hci_rp_read_local_oob_data {
__u8 status;
__u8 hash[16];
__u8 randomizer[16];
} __packed;
#define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58 #define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58
#define HCI_OP_READ_LOCAL_VERSION 0x1001 #define HCI_OP_READ_LOCAL_VERSION 0x1001
...@@ -745,7 +776,7 @@ struct hci_ev_auth_complete { ...@@ -745,7 +776,7 @@ struct hci_ev_auth_complete {
struct hci_ev_remote_name { struct hci_ev_remote_name {
__u8 status; __u8 status;
bdaddr_t bdaddr; bdaddr_t bdaddr;
__u8 name[248]; __u8 name[HCI_MAX_NAME_LENGTH];
} __packed; } __packed;
#define HCI_EV_ENCRYPT_CHANGE 0x08 #define HCI_EV_ENCRYPT_CHANGE 0x08
...@@ -953,6 +984,11 @@ struct hci_ev_user_confirm_req { ...@@ -953,6 +984,11 @@ struct hci_ev_user_confirm_req {
__le32 passkey; __le32 passkey;
} __packed; } __packed;
#define HCI_EV_REMOTE_OOB_DATA_REQUEST 0x35
struct hci_ev_remote_oob_data_request {
bdaddr_t bdaddr;
} __packed;
#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36 #define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36
struct hci_ev_simple_pair_complete { struct hci_ev_simple_pair_complete {
__u8 status; __u8 status;
......
...@@ -82,6 +82,13 @@ struct link_key { ...@@ -82,6 +82,13 @@ struct link_key {
u8 pin_len; u8 pin_len;
}; };
struct oob_data {
struct list_head list;
bdaddr_t bdaddr;
u8 hash[16];
u8 randomizer[16];
};
#define NUM_REASSEMBLY 4 #define NUM_REASSEMBLY 4
struct hci_dev { struct hci_dev {
struct list_head list; struct list_head list;
...@@ -94,7 +101,8 @@ struct hci_dev { ...@@ -94,7 +101,8 @@ struct hci_dev {
__u8 bus; __u8 bus;
__u8 dev_type; __u8 dev_type;
bdaddr_t bdaddr; bdaddr_t bdaddr;
__u8 dev_name[248]; __u8 dev_name[HCI_MAX_NAME_LENGTH];
__u8 eir[HCI_MAX_EIR_LENGTH];
__u8 dev_class[3]; __u8 dev_class[3];
__u8 major_class; __u8 major_class;
__u8 minor_class; __u8 minor_class;
...@@ -169,6 +177,8 @@ struct hci_dev { ...@@ -169,6 +177,8 @@ struct hci_dev {
struct list_head link_keys; struct list_head link_keys;
struct list_head remote_oob_data;
struct hci_dev_stats stat; struct hci_dev_stats stat;
struct sk_buff_head driver_init; struct sk_buff_head driver_init;
...@@ -505,6 +515,13 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, ...@@ -505,6 +515,13 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
u8 *key, u8 type, u8 pin_len); u8 *key, u8 type, u8 pin_len);
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_remote_oob_data_clear(struct hci_dev *hdev);
struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
bdaddr_t *bdaddr);
int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
u8 *randomizer);
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
void hci_del_off_timer(struct hci_dev *hdev); void hci_del_off_timer(struct hci_dev *hdev);
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
...@@ -767,6 +784,12 @@ int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); ...@@ -767,6 +784,12 @@ int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
u8 status); u8 status);
int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status);
int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
u8 status);
int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
u8 *eir);
int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
/* HCI info for socket */ /* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk) #define hci_pi(sk) ((struct hci_pinfo *) sk)
......
...@@ -280,7 +280,6 @@ struct l2cap_conn_param_update_rsp { ...@@ -280,7 +280,6 @@ struct l2cap_conn_param_update_rsp {
struct l2cap_chan_list { struct l2cap_chan_list {
struct sock *head; struct sock *head;
rwlock_t lock; rwlock_t lock;
long num;
}; };
struct l2cap_conn { struct l2cap_conn {
...@@ -302,7 +301,6 @@ struct l2cap_conn { ...@@ -302,7 +301,6 @@ struct l2cap_conn {
struct sk_buff *rx_skb; struct sk_buff *rx_skb;
__u32 rx_len; __u32 rx_len;
__u8 rx_ident;
__u8 tx_ident; __u8 tx_ident;
__u8 disc_reason; __u8 disc_reason;
......
...@@ -41,6 +41,10 @@ struct mgmt_rp_read_index_list { ...@@ -41,6 +41,10 @@ struct mgmt_rp_read_index_list {
__le16 index[0]; __le16 index[0];
} __packed; } __packed;
/* Reserve one extra byte for names in management messages so that they
* are always guaranteed to be nul-terminated */
#define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1)
#define MGMT_OP_READ_INFO 0x0004 #define MGMT_OP_READ_INFO 0x0004
struct mgmt_rp_read_info { struct mgmt_rp_read_info {
__u8 type; __u8 type;
...@@ -55,6 +59,7 @@ struct mgmt_rp_read_info { ...@@ -55,6 +59,7 @@ struct mgmt_rp_read_info {
__u16 manufacturer; __u16 manufacturer;
__u8 hci_ver; __u8 hci_ver;
__u16 hci_rev; __u16 hci_rev;
__u8 name[MGMT_MAX_NAME_LENGTH];
} __packed; } __packed;
struct mgmt_mode { struct mgmt_mode {
...@@ -167,6 +172,29 @@ struct mgmt_rp_user_confirm_reply { ...@@ -167,6 +172,29 @@ struct mgmt_rp_user_confirm_reply {
#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x0016 #define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x0016
#define MGMT_OP_SET_LOCAL_NAME 0x0017
struct mgmt_cp_set_local_name {
__u8 name[MGMT_MAX_NAME_LENGTH];
} __packed;
#define MGMT_OP_READ_LOCAL_OOB_DATA 0x0018
struct mgmt_rp_read_local_oob_data {
__u8 hash[16];
__u8 randomizer[16];
} __packed;
#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0019
struct mgmt_cp_add_remote_oob_data {
bdaddr_t bdaddr;
__u8 hash[16];
__u8 randomizer[16];
} __packed;
#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x001A
struct mgmt_cp_remove_remote_oob_data {
bdaddr_t bdaddr;
} __packed;
#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;
...@@ -234,3 +262,22 @@ struct mgmt_ev_auth_failed { ...@@ -234,3 +262,22 @@ struct mgmt_ev_auth_failed {
bdaddr_t bdaddr; bdaddr_t bdaddr;
__u8 status; __u8 status;
} __packed; } __packed;
#define MGMT_EV_LOCAL_NAME_CHANGED 0x0011
struct mgmt_ev_local_name_changed {
__u8 name[MGMT_MAX_NAME_LENGTH];
} __packed;
#define MGMT_EV_DEVICE_FOUND 0x0012
struct mgmt_ev_device_found {
bdaddr_t bdaddr;
__u8 dev_class[3];
__s8 rssi;
__u8 eir[HCI_MAX_EIR_LENGTH];
} __packed;
#define MGMT_EV_REMOTE_NAME 0x0013
struct mgmt_ev_remote_name {
bdaddr_t bdaddr;
__u8 name[MGMT_MAX_NAME_LENGTH];
} __packed;
...@@ -23,88 +23,88 @@ ...@@ -23,88 +23,88 @@
#include <linux/crc32.h> #include <linux/crc32.h>
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
// Limits /* Limits */
#define BNEP_MAX_PROTO_FILTERS 5 #define BNEP_MAX_PROTO_FILTERS 5
#define BNEP_MAX_MULTICAST_FILTERS 20 #define BNEP_MAX_MULTICAST_FILTERS 20
// UUIDs /* UUIDs */
#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB #define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
#define BNEP_UUID16 0x02 #define BNEP_UUID16 0x02
#define BNEP_UUID32 0x04 #define BNEP_UUID32 0x04
#define BNEP_UUID128 0x16 #define BNEP_UUID128 0x16
#define BNEP_SVC_PANU 0x1115 #define BNEP_SVC_PANU 0x1115
#define BNEP_SVC_NAP 0x1116 #define BNEP_SVC_NAP 0x1116
#define BNEP_SVC_GN 0x1117 #define BNEP_SVC_GN 0x1117
// Packet types /* Packet types */
#define BNEP_GENERAL 0x00 #define BNEP_GENERAL 0x00
#define BNEP_CONTROL 0x01 #define BNEP_CONTROL 0x01
#define BNEP_COMPRESSED 0x02 #define BNEP_COMPRESSED 0x02
#define BNEP_COMPRESSED_SRC_ONLY 0x03 #define BNEP_COMPRESSED_SRC_ONLY 0x03
#define BNEP_COMPRESSED_DST_ONLY 0x04 #define BNEP_COMPRESSED_DST_ONLY 0x04
// Control types /* Control types */
#define BNEP_CMD_NOT_UNDERSTOOD 0x00 #define BNEP_CMD_NOT_UNDERSTOOD 0x00
#define BNEP_SETUP_CONN_REQ 0x01 #define BNEP_SETUP_CONN_REQ 0x01
#define BNEP_SETUP_CONN_RSP 0x02 #define BNEP_SETUP_CONN_RSP 0x02
#define BNEP_FILTER_NET_TYPE_SET 0x03 #define BNEP_FILTER_NET_TYPE_SET 0x03
#define BNEP_FILTER_NET_TYPE_RSP 0x04 #define BNEP_FILTER_NET_TYPE_RSP 0x04
#define BNEP_FILTER_MULTI_ADDR_SET 0x05 #define BNEP_FILTER_MULTI_ADDR_SET 0x05
#define BNEP_FILTER_MULTI_ADDR_RSP 0x06 #define BNEP_FILTER_MULTI_ADDR_RSP 0x06
// Extension types /* Extension types */
#define BNEP_EXT_CONTROL 0x00 #define BNEP_EXT_CONTROL 0x00
// Response messages /* Response messages */
#define BNEP_SUCCESS 0x00 #define BNEP_SUCCESS 0x00
#define BNEP_CONN_INVALID_DST 0x01 #define BNEP_CONN_INVALID_DST 0x01
#define BNEP_CONN_INVALID_SRC 0x02 #define BNEP_CONN_INVALID_SRC 0x02
#define BNEP_CONN_INVALID_SVC 0x03 #define BNEP_CONN_INVALID_SVC 0x03
#define BNEP_CONN_NOT_ALLOWED 0x04 #define BNEP_CONN_NOT_ALLOWED 0x04
#define BNEP_FILTER_UNSUPPORTED_REQ 0x01 #define BNEP_FILTER_UNSUPPORTED_REQ 0x01
#define BNEP_FILTER_INVALID_RANGE 0x02 #define BNEP_FILTER_INVALID_RANGE 0x02
#define BNEP_FILTER_INVALID_MCADDR 0x02 #define BNEP_FILTER_INVALID_MCADDR 0x02
#define BNEP_FILTER_LIMIT_REACHED 0x03 #define BNEP_FILTER_LIMIT_REACHED 0x03
#define BNEP_FILTER_DENIED_SECURITY 0x04 #define BNEP_FILTER_DENIED_SECURITY 0x04
// L2CAP settings /* L2CAP settings */
#define BNEP_MTU 1691 #define BNEP_MTU 1691
#define BNEP_PSM 0x0f #define BNEP_PSM 0x0f
#define BNEP_FLUSH_TO 0xffff #define BNEP_FLUSH_TO 0xffff
#define BNEP_CONNECT_TO 15 #define BNEP_CONNECT_TO 15
#define BNEP_FILTER_TO 15 #define BNEP_FILTER_TO 15
// Headers /* Headers */
#define BNEP_TYPE_MASK 0x7f #define BNEP_TYPE_MASK 0x7f
#define BNEP_EXT_HEADER 0x80 #define BNEP_EXT_HEADER 0x80
struct bnep_setup_conn_req { struct bnep_setup_conn_req {
__u8 type; __u8 type;
__u8 ctrl; __u8 ctrl;
__u8 uuid_size; __u8 uuid_size;
__u8 service[0]; __u8 service[0];
} __packed; } __packed;
struct bnep_set_filter_req { struct bnep_set_filter_req {
__u8 type; __u8 type;
__u8 ctrl; __u8 ctrl;
__be16 len; __be16 len;
__u8 list[0]; __u8 list[0];
} __packed; } __packed;
struct bnep_control_rsp { struct bnep_control_rsp {
__u8 type; __u8 type;
__u8 ctrl; __u8 ctrl;
__be16 resp; __be16 resp;
} __packed; } __packed;
struct bnep_ext_hdr { struct bnep_ext_hdr {
__u8 type; __u8 type;
__u8 len; __u8 len;
__u8 data[0]; __u8 data[0];
} __packed; } __packed;
/* BNEP ioctl defines */ /* BNEP ioctl defines */
...@@ -114,10 +114,10 @@ struct bnep_ext_hdr { ...@@ -114,10 +114,10 @@ struct bnep_ext_hdr {
#define BNEPGETCONNINFO _IOR('B', 211, int) #define BNEPGETCONNINFO _IOR('B', 211, int)
struct bnep_connadd_req { struct bnep_connadd_req {
int sock; // Connected socket int sock; /* Connected socket */
__u32 flags; __u32 flags;
__u16 role; __u16 role;
char device[16]; // Name of the Ethernet device char device[16]; /* Name of the Ethernet device */
}; };
struct bnep_conndel_req { struct bnep_conndel_req {
...@@ -148,14 +148,14 @@ int bnep_del_connection(struct bnep_conndel_req *req); ...@@ -148,14 +148,14 @@ int bnep_del_connection(struct bnep_conndel_req *req);
int bnep_get_connlist(struct bnep_connlist_req *req); int bnep_get_connlist(struct bnep_connlist_req *req);
int bnep_get_conninfo(struct bnep_conninfo *ci); int bnep_get_conninfo(struct bnep_conninfo *ci);
// BNEP sessions /* BNEP sessions */
struct bnep_session { struct bnep_session {
struct list_head list; struct list_head list;
unsigned int role; unsigned int role;
unsigned long state; unsigned long state;
unsigned long flags; unsigned long flags;
atomic_t killed; struct task_struct *task;
struct ethhdr eh; struct ethhdr eh;
struct msghdr msg; struct msghdr msg;
...@@ -173,7 +173,7 @@ void bnep_sock_cleanup(void); ...@@ -173,7 +173,7 @@ void bnep_sock_cleanup(void);
static inline int bnep_mc_hash(__u8 *addr) static inline int bnep_mc_hash(__u8 *addr)
{ {
return (crc32_be(~0, addr, ETH_ALEN) >> 26); return crc32_be(~0, addr, ETH_ALEN) >> 26;
} }
#endif #endif
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/net.h> #include <linux/net.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/kthread.h>
#include <net/sock.h> #include <net/sock.h>
#include <linux/socket.h> #include <linux/socket.h>
...@@ -131,7 +132,8 @@ static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len ...@@ -131,7 +132,8 @@ static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len
return -EILSEQ; return -EILSEQ;
n = get_unaligned_be16(data); n = get_unaligned_be16(data);
data++; len -= 2; data++;
len -= 2;
if (len < n) if (len < n)
return -EILSEQ; return -EILSEQ;
...@@ -176,7 +178,8 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) ...@@ -176,7 +178,8 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
return -EILSEQ; return -EILSEQ;
n = get_unaligned_be16(data); n = get_unaligned_be16(data);
data += 2; len -= 2; data += 2;
len -= 2;
if (len < n) if (len < n)
return -EILSEQ; return -EILSEQ;
...@@ -187,6 +190,8 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) ...@@ -187,6 +190,8 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
n /= (ETH_ALEN * 2); n /= (ETH_ALEN * 2);
if (n > 0) { if (n > 0) {
int i;
s->mc_filter = 0; s->mc_filter = 0;
/* Always send broadcast */ /* Always send broadcast */
...@@ -196,18 +201,22 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) ...@@ -196,18 +201,22 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
for (; n > 0; n--) { for (; n > 0; n--) {
u8 a1[6], *a2; u8 a1[6], *a2;
memcpy(a1, data, ETH_ALEN); data += ETH_ALEN; memcpy(a1, data, ETH_ALEN);
a2 = data; data += ETH_ALEN; data += ETH_ALEN;
a2 = data;
data += ETH_ALEN;
BT_DBG("mc filter %s -> %s", BT_DBG("mc filter %s -> %s",
batostr((void *) a1), batostr((void *) a2)); batostr((void *) a1), batostr((void *) a2));
#define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); }
/* Iterate from a1 to a2 */ /* Iterate from a1 to a2 */
set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter); set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) { while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
INCA(a1); /* Increment a1 */
i = 5;
while (i >= 0 && ++a1[i--] == 0)
;
set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter); set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
} }
} }
...@@ -227,7 +236,8 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) ...@@ -227,7 +236,8 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len)
u8 cmd = *(u8 *)data; u8 cmd = *(u8 *)data;
int err = 0; int err = 0;
data++; len--; data++;
len--;
switch (cmd) { switch (cmd) {
case BNEP_CMD_NOT_UNDERSTOOD: case BNEP_CMD_NOT_UNDERSTOOD:
...@@ -302,7 +312,6 @@ static u8 __bnep_rx_hlen[] = { ...@@ -302,7 +312,6 @@ static u8 __bnep_rx_hlen[] = {
ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */ ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */ ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */
}; };
#define BNEP_RX_TYPES (sizeof(__bnep_rx_hlen) - 1)
static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
{ {
...@@ -312,9 +321,10 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) ...@@ -312,9 +321,10 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
dev->stats.rx_bytes += skb->len; dev->stats.rx_bytes += skb->len;
type = *(u8 *) skb->data; skb_pull(skb, 1); type = *(u8 *) skb->data;
skb_pull(skb, 1);
if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES) if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen))
goto badframe; goto badframe;
if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) { if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
...@@ -367,14 +377,14 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) ...@@ -367,14 +377,14 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
case BNEP_COMPRESSED_DST_ONLY: case BNEP_COMPRESSED_DST_ONLY:
memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb),
ETH_ALEN); ETH_ALEN);
memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source, memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source,
ETH_ALEN + 2); ETH_ALEN + 2);
break; break;
case BNEP_GENERAL: case BNEP_GENERAL:
memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb), memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb),
ETH_ALEN * 2); ETH_ALEN * 2);
put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2)); put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
break; break;
} }
...@@ -470,15 +480,14 @@ static int bnep_session(void *arg) ...@@ -470,15 +480,14 @@ static int bnep_session(void *arg)
BT_DBG(""); BT_DBG("");
daemonize("kbnepd %s", dev->name);
set_user_nice(current, -15); set_user_nice(current, -15);
init_waitqueue_entry(&wait, current); init_waitqueue_entry(&wait, current);
add_wait_queue(sk_sleep(sk), &wait); add_wait_queue(sk_sleep(sk), &wait);
while (!atomic_read(&s->killed)) { while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
// RX /* RX */
while ((skb = skb_dequeue(&sk->sk_receive_queue))) { while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb); skb_orphan(skb);
bnep_rx_frame(s, skb); bnep_rx_frame(s, skb);
...@@ -487,7 +496,7 @@ static int bnep_session(void *arg) ...@@ -487,7 +496,7 @@ static int bnep_session(void *arg)
if (sk->sk_state != BT_CONNECTED) if (sk->sk_state != BT_CONNECTED)
break; break;
// TX /* TX */
while ((skb = skb_dequeue(&sk->sk_write_queue))) while ((skb = skb_dequeue(&sk->sk_write_queue)))
if (bnep_tx_frame(s, skb)) if (bnep_tx_frame(s, skb))
break; break;
...@@ -555,8 +564,8 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) ...@@ -555,8 +564,8 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
/* session struct allocated as private part of net_device */ /* session struct allocated as private part of net_device */
dev = alloc_netdev(sizeof(struct bnep_session), dev = alloc_netdev(sizeof(struct bnep_session),
(*req->device) ? req->device : "bnep%d", (*req->device) ? req->device : "bnep%d",
bnep_net_setup); bnep_net_setup);
if (!dev) if (!dev)
return -ENOMEM; return -ENOMEM;
...@@ -571,7 +580,7 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) ...@@ -571,7 +580,7 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
s = netdev_priv(dev); s = netdev_priv(dev);
/* This is rx header therefore addresses are swapped. /* This is rx header therefore addresses are swapped.
* ie eh.h_dest is our local address. */ * ie. eh.h_dest is our local address. */
memcpy(s->eh.h_dest, &src, ETH_ALEN); memcpy(s->eh.h_dest, &src, ETH_ALEN);
memcpy(s->eh.h_source, &dst, ETH_ALEN); memcpy(s->eh.h_source, &dst, ETH_ALEN);
memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN); memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
...@@ -597,17 +606,17 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) ...@@ -597,17 +606,17 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
SET_NETDEV_DEVTYPE(dev, &bnep_type); SET_NETDEV_DEVTYPE(dev, &bnep_type);
err = register_netdev(dev); err = register_netdev(dev);
if (err) { if (err)
goto failed; goto failed;
}
__bnep_link_session(s); __bnep_link_session(s);
err = kernel_thread(bnep_session, s, CLONE_KERNEL); s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
if (err < 0) { if (IS_ERR(s->task)) {
/* Session thread start failed, gotta cleanup. */ /* Session thread start failed, gotta cleanup. */
unregister_netdev(dev); unregister_netdev(dev);
__bnep_unlink_session(s); __bnep_unlink_session(s);
err = PTR_ERR(s->task);
goto failed; goto failed;
} }
...@@ -631,15 +640,9 @@ int bnep_del_connection(struct bnep_conndel_req *req) ...@@ -631,15 +640,9 @@ int bnep_del_connection(struct bnep_conndel_req *req)
down_read(&bnep_session_sem); down_read(&bnep_session_sem);
s = __bnep_get_session(req->dst); s = __bnep_get_session(req->dst);
if (s) { if (s)
/* Wakeup user-space which is polling for socket errors. kthread_stop(s->task);
* This is temporary hack until we have shutdown in L2CAP */ else
s->sock->sk->sk_err = EUNATCH;
/* Kill session thread */
atomic_inc(&s->killed);
wake_up_interruptible(sk_sleep(s->sock->sk));
} else
err = -ENOENT; err = -ENOENT;
up_read(&bnep_session_sem); up_read(&bnep_session_sem);
......
...@@ -39,10 +39,10 @@ ...@@ -39,10 +39,10 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/uaccess.h>
#include <net/sock.h> #include <net/sock.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h>
#include "bnep.h" #include "bnep.h"
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/kthread.h>
#include <net/sock.h> #include <net/sock.h>
#include <linux/isdn/capilli.h> #include <linux/isdn/capilli.h>
...@@ -143,7 +144,7 @@ static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb) ...@@ -143,7 +144,7 @@ static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
skb_queue_tail(&session->transmit, skb); skb_queue_tail(&session->transmit, skb);
cmtp_schedule(session); wake_up_interruptible(sk_sleep(session->sock->sk));
} }
static void cmtp_send_interopmsg(struct cmtp_session *session, static void cmtp_send_interopmsg(struct cmtp_session *session,
...@@ -386,8 +387,7 @@ static void cmtp_reset_ctr(struct capi_ctr *ctrl) ...@@ -386,8 +387,7 @@ static void cmtp_reset_ctr(struct capi_ctr *ctrl)
capi_ctr_down(ctrl); capi_ctr_down(ctrl);
atomic_inc(&session->terminate); kthread_stop(session->task);
cmtp_schedule(session);
} }
static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp) static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
#define CMTP_LOOPBACK 0 #define CMTP_LOOPBACK 0
struct cmtp_connadd_req { struct cmtp_connadd_req {
int sock; // Connected socket int sock; /* Connected socket */
__u32 flags; __u32 flags;
}; };
...@@ -81,7 +81,7 @@ struct cmtp_session { ...@@ -81,7 +81,7 @@ struct cmtp_session {
char name[BTNAMSIZ]; char name[BTNAMSIZ];
atomic_t terminate; struct task_struct *task;
wait_queue_head_t wait; wait_queue_head_t wait;
...@@ -121,13 +121,6 @@ void cmtp_detach_device(struct cmtp_session *session); ...@@ -121,13 +121,6 @@ void cmtp_detach_device(struct cmtp_session *session);
void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb); void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb);
static inline void cmtp_schedule(struct cmtp_session *session)
{
struct sock *sk = session->sock->sk;
wake_up_interruptible(sk_sleep(sk));
}
/* CMTP init defines */ /* CMTP init defines */
int cmtp_init_sockets(void); int cmtp_init_sockets(void);
void cmtp_cleanup_sockets(void); void cmtp_cleanup_sockets(void);
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kthread.h>
#include <net/sock.h> #include <net/sock.h>
#include <linux/isdn/capilli.h> #include <linux/isdn/capilli.h>
...@@ -235,9 +236,12 @@ static void cmtp_process_transmit(struct cmtp_session *session) ...@@ -235,9 +236,12 @@ static void cmtp_process_transmit(struct cmtp_session *session)
size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len); size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) { if (scb->id < 0) {
skb_queue_head(&session->transmit, skb); scb->id = cmtp_alloc_block_id(session);
break; if (scb->id < 0) {
skb_queue_head(&session->transmit, skb);
break;
}
} }
if (size < 256) { if (size < 256) {
...@@ -284,12 +288,11 @@ static int cmtp_session(void *arg) ...@@ -284,12 +288,11 @@ static int cmtp_session(void *arg)
BT_DBG("session %p", session); BT_DBG("session %p", session);
daemonize("kcmtpd_ctr_%d", session->num);
set_user_nice(current, -15); set_user_nice(current, -15);
init_waitqueue_entry(&wait, current); init_waitqueue_entry(&wait, current);
add_wait_queue(sk_sleep(sk), &wait); add_wait_queue(sk_sleep(sk), &wait);
while (!atomic_read(&session->terminate)) { while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (sk->sk_state != BT_CONNECTED) if (sk->sk_state != BT_CONNECTED)
...@@ -367,9 +370,12 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) ...@@ -367,9 +370,12 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
__cmtp_link_session(session); __cmtp_link_session(session);
err = kernel_thread(cmtp_session, session, CLONE_KERNEL); session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d",
if (err < 0) session->num);
if (IS_ERR(session->task)) {
err = PTR_ERR(session->task);
goto unlink; goto unlink;
}
if (!(session->flags & (1 << CMTP_LOOPBACK))) { if (!(session->flags & (1 << CMTP_LOOPBACK))) {
err = cmtp_attach_device(session); err = cmtp_attach_device(session);
...@@ -406,9 +412,8 @@ int cmtp_del_connection(struct cmtp_conndel_req *req) ...@@ -406,9 +412,8 @@ int cmtp_del_connection(struct cmtp_conndel_req *req)
/* Flush the transmit queue */ /* Flush the transmit queue */
skb_queue_purge(&session->transmit); skb_queue_purge(&session->transmit);
/* Kill session thread */ /* Stop session thread */
atomic_inc(&session->terminate); kthread_stop(session->task);
cmtp_schedule(session);
} else } else
err = -ENOENT; err = -ENOENT;
......
...@@ -34,12 +34,12 @@ ...@@ -34,12 +34,12 @@
#include <linux/file.h> #include <linux/file.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/uaccess.h>
#include <net/sock.h> #include <net/sock.h>
#include <linux/isdn/capilli.h> #include <linux/isdn/capilli.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h>
#include "cmtp.h" #include "cmtp.h"
......
...@@ -56,7 +56,6 @@ ...@@ -56,7 +56,6 @@
static void hci_cmd_task(unsigned long arg); static void hci_cmd_task(unsigned long arg);
static void hci_rx_task(unsigned long arg); static void hci_rx_task(unsigned long arg);
static void hci_tx_task(unsigned long arg); static void hci_tx_task(unsigned long arg);
static void hci_notify(struct hci_dev *hdev, int event);
static DEFINE_RWLOCK(hci_task_lock); static DEFINE_RWLOCK(hci_task_lock);
...@@ -186,6 +185,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt) ...@@ -186,6 +185,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
BT_DBG("%s %ld", hdev->name, opt); BT_DBG("%s %ld", hdev->name, opt);
/* Reset device */ /* Reset device */
set_bit(HCI_RESET, &hdev->flags);
hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
} }
...@@ -213,8 +213,10 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) ...@@ -213,8 +213,10 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
/* Mandatory initialization */ /* Mandatory initialization */
/* Reset */ /* Reset */
if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
set_bit(HCI_RESET, &hdev->flags);
hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
}
/* Read Local Supported Features */ /* Read Local Supported Features */
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL); hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
...@@ -584,6 +586,9 @@ static int hci_dev_do_close(struct hci_dev *hdev) ...@@ -584,6 +586,9 @@ static int hci_dev_do_close(struct hci_dev *hdev)
hci_req_cancel(hdev, ENODEV); hci_req_cancel(hdev, ENODEV);
hci_req_lock(hdev); hci_req_lock(hdev);
/* Stop timer, it might be running */
del_timer_sync(&hdev->cmd_timer);
if (!test_and_clear_bit(HCI_UP, &hdev->flags)) { if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
hci_req_unlock(hdev); hci_req_unlock(hdev);
return 0; return 0;
...@@ -623,7 +628,6 @@ static int hci_dev_do_close(struct hci_dev *hdev) ...@@ -623,7 +628,6 @@ 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;
} }
...@@ -1074,9 +1078,74 @@ static void hci_cmd_timer(unsigned long arg) ...@@ -1074,9 +1078,74 @@ static void hci_cmd_timer(unsigned long arg)
BT_ERR("%s command tx timeout", hdev->name); BT_ERR("%s command tx timeout", hdev->name);
atomic_set(&hdev->cmd_cnt, 1); atomic_set(&hdev->cmd_cnt, 1);
clear_bit(HCI_RESET, &hdev->flags);
tasklet_schedule(&hdev->cmd_task); tasklet_schedule(&hdev->cmd_task);
} }
struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
bdaddr_t *bdaddr)
{
struct oob_data *data;
list_for_each_entry(data, &hdev->remote_oob_data, list)
if (bacmp(bdaddr, &data->bdaddr) == 0)
return data;
return NULL;
}
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct oob_data *data;
data = hci_find_remote_oob_data(hdev, bdaddr);
if (!data)
return -ENOENT;
BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
list_del(&data->list);
kfree(data);
return 0;
}
int hci_remote_oob_data_clear(struct hci_dev *hdev)
{
struct oob_data *data, *n;
list_for_each_entry_safe(data, n, &hdev->remote_oob_data, list) {
list_del(&data->list);
kfree(data);
}
return 0;
}
int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
u8 *randomizer)
{
struct oob_data *data;
data = hci_find_remote_oob_data(hdev, bdaddr);
if (!data) {
data = kmalloc(sizeof(*data), GFP_ATOMIC);
if (!data)
return -ENOMEM;
bacpy(&data->bdaddr, bdaddr);
list_add(&data->list, &hdev->remote_oob_data);
}
memcpy(data->hash, hash, sizeof(data->hash));
memcpy(data->randomizer, randomizer, sizeof(data->randomizer));
BT_DBG("%s for %s", hdev->name, batostr(bdaddr));
return 0;
}
/* Register HCI device */ /* Register HCI device */
int hci_register_dev(struct hci_dev *hdev) int hci_register_dev(struct hci_dev *hdev)
{ {
...@@ -1141,6 +1210,8 @@ int hci_register_dev(struct hci_dev *hdev) ...@@ -1141,6 +1210,8 @@ int hci_register_dev(struct hci_dev *hdev)
INIT_LIST_HEAD(&hdev->link_keys); INIT_LIST_HEAD(&hdev->link_keys);
INIT_LIST_HEAD(&hdev->remote_oob_data);
INIT_WORK(&hdev->power_on, hci_power_on); INIT_WORK(&hdev->power_on, hci_power_on);
INIT_WORK(&hdev->power_off, hci_power_off); INIT_WORK(&hdev->power_off, hci_power_off);
setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev); setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
...@@ -1220,6 +1291,7 @@ int hci_unregister_dev(struct hci_dev *hdev) ...@@ -1220,6 +1291,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_blacklist_clear(hdev); hci_blacklist_clear(hdev);
hci_uuids_clear(hdev); hci_uuids_clear(hdev);
hci_link_keys_clear(hdev); hci_link_keys_clear(hdev);
hci_remote_oob_data_clear(hdev);
hci_dev_unlock_bh(hdev); hci_dev_unlock_bh(hdev);
__hci_dev_put(hdev); __hci_dev_put(hdev);
...@@ -1269,7 +1341,7 @@ int hci_recv_frame(struct sk_buff *skb) ...@@ -1269,7 +1341,7 @@ int hci_recv_frame(struct sk_buff *skb)
EXPORT_SYMBOL(hci_recv_frame); EXPORT_SYMBOL(hci_recv_frame);
static int hci_reassembly(struct hci_dev *hdev, int type, void *data, static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
int count, __u8 index, gfp_t gfp_mask) int count, __u8 index)
{ {
int len = 0; int len = 0;
int hlen = 0; int hlen = 0;
...@@ -1299,7 +1371,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data, ...@@ -1299,7 +1371,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
break; break;
} }
skb = bt_skb_alloc(len, gfp_mask); skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!skb) if (!skb)
return -ENOMEM; return -ENOMEM;
...@@ -1385,8 +1457,7 @@ int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count) ...@@ -1385,8 +1457,7 @@ int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
return -EILSEQ; return -EILSEQ;
while (count) { while (count) {
rem = hci_reassembly(hdev, type, data, count, rem = hci_reassembly(hdev, type, data, count, type - 1);
type - 1, GFP_ATOMIC);
if (rem < 0) if (rem < 0)
return rem; return rem;
...@@ -1420,8 +1491,8 @@ int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count) ...@@ -1420,8 +1491,8 @@ int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
} else } else
type = bt_cb(skb)->pkt_type; type = bt_cb(skb)->pkt_type;
rem = hci_reassembly(hdev, type, data, rem = hci_reassembly(hdev, type, data, count,
count, STREAM_REASSEMBLY, GFP_ATOMIC); STREAM_REASSEMBLY);
if (rem < 0) if (rem < 0)
return rem; return rem;
......
...@@ -183,6 +183,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -183,6 +183,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%x", hdev->name, status); BT_DBG("%s status 0x%x", hdev->name, status);
clear_bit(HCI_RESET, &hdev->flags);
hci_req_complete(hdev, HCI_OP_RESET, status); hci_req_complete(hdev, HCI_OP_RESET, status);
} }
...@@ -193,14 +195,17 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -193,14 +195,17 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%x", hdev->name, status); BT_DBG("%s status 0x%x", hdev->name, status);
if (status)
return;
sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
if (!sent) if (!sent)
return; return;
memcpy(hdev->dev_name, sent, 248); if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_set_local_name_complete(hdev->id, sent, status);
if (status)
return;
memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
} }
static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -212,7 +217,7 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -212,7 +217,7 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
if (rp->status) if (rp->status)
return; return;
memcpy(hdev->dev_name, rp->name, 248); memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH);
} }
static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -819,6 +824,17 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev, ...@@ -819,6 +824,17 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
rp->status); rp->status);
} }
static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
mgmt_read_local_oob_data_reply_complete(hdev->id, rp->hash,
rp->randomizer, 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)
{ {
BT_DBG("%s status 0x%x", hdev->name, status); BT_DBG("%s status 0x%x", hdev->name, status);
...@@ -1212,7 +1228,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * ...@@ -1212,7 +1228,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
hci_dev_lock(hdev); hci_dev_lock(hdev);
for (; num_rsp; num_rsp--) { for (; num_rsp; num_rsp--, info++) {
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;
...@@ -1221,8 +1237,9 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * ...@@ -1221,8 +1237,9 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
data.clock_offset = info->clock_offset; data.clock_offset = info->clock_offset;
data.rssi = 0x00; data.rssi = 0x00;
data.ssp_mode = 0x00; data.ssp_mode = 0x00;
info++;
hci_inquiry_cache_update(hdev, &data); hci_inquiry_cache_update(hdev, &data);
mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, 0,
NULL);
} }
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -1480,6 +1497,9 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb ...@@ -1480,6 +1497,9 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (ev->status == 0 && test_bit(HCI_MGMT, &hdev->flags))
mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (conn && hci_outgoing_auth_needed(hdev, conn)) { if (conn && hci_outgoing_auth_needed(hdev, conn)) {
struct hci_cp_auth_requested cp; struct hci_cp_auth_requested cp;
...@@ -1749,6 +1769,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk ...@@ -1749,6 +1769,10 @@ 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_READ_LOCAL_OOB_DATA:
hci_cc_read_local_oob_data_reply(hdev, skb);
break;
case HCI_OP_LE_READ_BUFFER_SIZE: case HCI_OP_LE_READ_BUFFER_SIZE:
hci_cc_le_read_buffer_size(hdev, skb); hci_cc_le_read_buffer_size(hdev, skb);
break; break;
...@@ -1847,7 +1871,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -1847,7 +1871,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
if (ev->opcode != HCI_OP_NOP) if (ev->opcode != HCI_OP_NOP)
del_timer(&hdev->cmd_timer); del_timer(&hdev->cmd_timer);
if (ev->ncmd) { if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
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))
tasklet_schedule(&hdev->cmd_task); tasklet_schedule(&hdev->cmd_task);
...@@ -2138,7 +2162,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct ...@@ -2138,7 +2162,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
struct inquiry_info_with_rssi_and_pscan_mode *info; struct inquiry_info_with_rssi_and_pscan_mode *info;
info = (void *) (skb->data + 1); info = (void *) (skb->data + 1);
for (; num_rsp; num_rsp--) { for (; num_rsp; num_rsp--, info++) {
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;
...@@ -2147,13 +2171,15 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct ...@@ -2147,13 +2171,15 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
data.clock_offset = info->clock_offset; data.clock_offset = info->clock_offset;
data.rssi = info->rssi; data.rssi = info->rssi;
data.ssp_mode = 0x00; data.ssp_mode = 0x00;
info++;
hci_inquiry_cache_update(hdev, &data); hci_inquiry_cache_update(hdev, &data);
mgmt_device_found(hdev->id, &info->bdaddr,
info->dev_class, info->rssi,
NULL);
} }
} else { } else {
struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
for (; num_rsp; num_rsp--) { for (; num_rsp; num_rsp--, info++) {
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;
...@@ -2162,8 +2188,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct ...@@ -2162,8 +2188,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
data.clock_offset = info->clock_offset; data.clock_offset = info->clock_offset;
data.rssi = info->rssi; data.rssi = info->rssi;
data.ssp_mode = 0x00; data.ssp_mode = 0x00;
info++;
hci_inquiry_cache_update(hdev, &data); hci_inquiry_cache_update(hdev, &data);
mgmt_device_found(hdev->id, &info->bdaddr,
info->dev_class, info->rssi,
NULL);
} }
} }
...@@ -2294,7 +2322,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct ...@@ -2294,7 +2322,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
hci_dev_lock(hdev); hci_dev_lock(hdev);
for (; num_rsp; num_rsp--) { for (; num_rsp; num_rsp--, info++) {
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;
...@@ -2303,8 +2331,9 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct ...@@ -2303,8 +2331,9 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
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++;
hci_inquiry_cache_update(hdev, &data); hci_inquiry_cache_update(hdev, &data);
mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class,
info->rssi, info->data);
} }
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -2353,9 +2382,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff ...@@ -2353,9 +2382,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
bacpy(&cp.bdaddr, &ev->bdaddr); bacpy(&cp.bdaddr, &ev->bdaddr);
cp.capability = conn->io_capability; cp.capability = conn->io_capability;
cp.oob_data = 0;
cp.authentication = hci_get_auth_req(conn); cp.authentication = hci_get_auth_req(conn);
if ((conn->out == 0x01 || conn->remote_oob == 0x01) &&
hci_find_remote_oob_data(hdev, &conn->dst))
cp.oob_data = 0x01;
else
cp.oob_data = 0x00;
hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY, hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY,
sizeof(cp), &cp); sizeof(cp), &cp);
} else { } else {
...@@ -2453,6 +2487,37 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_ ...@@ -2453,6 +2487,37 @@ 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_remote_oob_data_request_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
struct oob_data *data;
BT_DBG("%s", hdev->name);
hci_dev_lock(hdev);
data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
if (data) {
struct hci_cp_remote_oob_data_reply cp;
bacpy(&cp.bdaddr, &ev->bdaddr);
memcpy(cp.hash, data->hash, sizeof(cp.hash));
memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp),
&cp);
} else {
struct hci_cp_remote_oob_data_neg_reply cp;
bacpy(&cp.bdaddr, &ev->bdaddr);
hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp),
&cp);
}
hci_dev_unlock(hdev);
}
static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) 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_ev_le_conn_complete *ev = (void *) skb->data;
...@@ -2655,6 +2720,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2655,6 +2720,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_le_meta_evt(hdev, skb); hci_le_meta_evt(hdev, skb);
break; break;
case HCI_EV_REMOTE_OOB_DATA_REQUEST:
hci_remote_oob_data_request_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;
......
...@@ -216,13 +216,13 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, char ...@@ -216,13 +216,13 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, char
static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
{ {
struct hci_dev *hdev = dev_get_drvdata(dev); struct hci_dev *hdev = dev_get_drvdata(dev);
char name[249]; char name[HCI_MAX_NAME_LENGTH + 1];
int i; int i;
for (i = 0; i < 248; i++) for (i = 0; i < HCI_MAX_NAME_LENGTH; i++)
name[i] = hdev->dev_name[i]; name[i] = hdev->dev_name[i];
name[248] = '\0'; name[HCI_MAX_NAME_LENGTH] = '\0';
return sprintf(buf, "%s\n", name); return sprintf(buf, "%s\n", name);
} }
...@@ -277,10 +277,12 @@ static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *at ...@@ -277,10 +277,12 @@ static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *at
static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{ {
struct hci_dev *hdev = dev_get_drvdata(dev); struct hci_dev *hdev = dev_get_drvdata(dev);
unsigned long val; unsigned int val;
int rv;
if (strict_strtoul(buf, 0, &val) < 0) rv = kstrtouint(buf, 0, &val);
return -EINVAL; if (rv < 0)
return rv;
if (val != 0 && (val < 500 || val > 3600000)) if (val != 0 && (val < 500 || val > 3600000))
return -EINVAL; return -EINVAL;
...@@ -299,15 +301,14 @@ static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribu ...@@ -299,15 +301,14 @@ static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribu
static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{ {
struct hci_dev *hdev = dev_get_drvdata(dev); struct hci_dev *hdev = dev_get_drvdata(dev);
unsigned long val; u16 val;
int rv;
if (strict_strtoul(buf, 0, &val) < 0)
return -EINVAL;
if (val < 0x0002 || val > 0xFFFE || val % 2) rv = kstrtou16(buf, 0, &val);
return -EINVAL; if (rv < 0)
return rv;
if (val < hdev->sniff_min_interval) if (val == 0 || val % 2 || val < hdev->sniff_min_interval)
return -EINVAL; return -EINVAL;
hdev->sniff_max_interval = val; hdev->sniff_max_interval = val;
...@@ -324,15 +325,14 @@ static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribu ...@@ -324,15 +325,14 @@ static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribu
static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{ {
struct hci_dev *hdev = dev_get_drvdata(dev); struct hci_dev *hdev = dev_get_drvdata(dev);
unsigned long val; u16 val;
int rv;
if (strict_strtoul(buf, 0, &val) < 0) rv = kstrtou16(buf, 0, &val);
return -EINVAL; if (rv < 0)
return rv;
if (val < 0x0002 || val > 0xFFFE || val % 2)
return -EINVAL;
if (val > hdev->sniff_max_interval) if (val == 0 || val % 2 || val > hdev->sniff_max_interval)
return -EINVAL; return -EINVAL;
hdev->sniff_min_interval = val; hdev->sniff_min_interval = val;
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/kthread.h>
#include <net/sock.h> #include <net/sock.h>
#include <linux/input.h> #include <linux/input.h>
...@@ -55,22 +56,24 @@ static DECLARE_RWSEM(hidp_session_sem); ...@@ -55,22 +56,24 @@ static DECLARE_RWSEM(hidp_session_sem);
static LIST_HEAD(hidp_session_list); static LIST_HEAD(hidp_session_list);
static unsigned char hidp_keycode[256] = { static unsigned char hidp_keycode[256] = {
0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36,
50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45,
4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1,
27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 14, 15, 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52,
65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88,
105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 99, 70, 119, 110, 102, 104, 111, 107, 109, 106, 105, 108, 103, 69,
72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73,
191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190,
115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, 191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135,
122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 113, 115, 114, 0, 0, 0, 121, 0, 89, 93, 124, 92, 94,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 122, 123, 90, 91, 85, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
150,158,159,128,136,177,178,176,142,152,173,140 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115,
114, 113, 150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140
}; };
static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
...@@ -461,8 +464,7 @@ static void hidp_idle_timeout(unsigned long arg) ...@@ -461,8 +464,7 @@ static void hidp_idle_timeout(unsigned long arg)
{ {
struct hidp_session *session = (struct hidp_session *) arg; struct hidp_session *session = (struct hidp_session *) arg;
atomic_inc(&session->terminate); kthread_stop(session->task);
hidp_schedule(session);
} }
static void hidp_set_timer(struct hidp_session *session) static void hidp_set_timer(struct hidp_session *session)
...@@ -533,9 +535,7 @@ static void hidp_process_hid_control(struct hidp_session *session, ...@@ -533,9 +535,7 @@ static void hidp_process_hid_control(struct hidp_session *session,
skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->ctrl_transmit);
skb_queue_purge(&session->intr_transmit); skb_queue_purge(&session->intr_transmit);
/* Kill session thread */ kthread_stop(session->task);
atomic_inc(&session->terminate);
hidp_schedule(session);
} }
} }
...@@ -694,22 +694,10 @@ static int hidp_session(void *arg) ...@@ -694,22 +694,10 @@ static int hidp_session(void *arg)
struct sock *ctrl_sk = session->ctrl_sock->sk; struct sock *ctrl_sk = session->ctrl_sock->sk;
struct sock *intr_sk = session->intr_sock->sk; struct sock *intr_sk = session->intr_sock->sk;
struct sk_buff *skb; struct sk_buff *skb;
int vendor = 0x0000, product = 0x0000;
wait_queue_t ctrl_wait, intr_wait; wait_queue_t ctrl_wait, intr_wait;
BT_DBG("session %p", session); BT_DBG("session %p", session);
if (session->input) {
vendor = session->input->id.vendor;
product = session->input->id.product;
}
if (session->hid) {
vendor = session->hid->vendor;
product = session->hid->product;
}
daemonize("khidpd_%04x%04x", vendor, product);
set_user_nice(current, -15); set_user_nice(current, -15);
init_waitqueue_entry(&ctrl_wait, current); init_waitqueue_entry(&ctrl_wait, current);
...@@ -718,10 +706,11 @@ static int hidp_session(void *arg) ...@@ -718,10 +706,11 @@ static int hidp_session(void *arg)
add_wait_queue(sk_sleep(intr_sk), &intr_wait); add_wait_queue(sk_sleep(intr_sk), &intr_wait);
session->waiting_for_startup = 0; session->waiting_for_startup = 0;
wake_up_interruptible(&session->startup_queue); wake_up_interruptible(&session->startup_queue);
while (!atomic_read(&session->terminate)) { while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED) if (ctrl_sk->sk_state != BT_CONNECTED ||
intr_sk->sk_state != BT_CONNECTED)
break; break;
while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) { while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
...@@ -965,6 +954,7 @@ static int hidp_setup_hid(struct hidp_session *session, ...@@ -965,6 +954,7 @@ static int hidp_setup_hid(struct hidp_session *session,
int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
{ {
struct hidp_session *session, *s; struct hidp_session *session, *s;
int vendor, product;
int err; int err;
BT_DBG(""); BT_DBG("");
...@@ -1026,9 +1016,24 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, ...@@ -1026,9 +1016,24 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
hidp_set_timer(session); hidp_set_timer(session);
err = kernel_thread(hidp_session, session, CLONE_KERNEL); if (session->hid) {
if (err < 0) vendor = session->hid->vendor;
product = session->hid->product;
} else if (session->input) {
vendor = session->input->id.vendor;
product = session->input->id.product;
} else {
vendor = 0x0000;
product = 0x0000;
}
session->task = kthread_run(hidp_session, session, "khidpd_%04x%04x",
vendor, product);
if (IS_ERR(session->task)) {
err = PTR_ERR(session->task);
goto unlink; goto unlink;
}
while (session->waiting_for_startup) { while (session->waiting_for_startup) {
wait_event_interruptible(session->startup_queue, wait_event_interruptible(session->startup_queue,
!session->waiting_for_startup); !session->waiting_for_startup);
...@@ -1053,8 +1058,7 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, ...@@ -1053,8 +1058,7 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
err_add_device: err_add_device:
hid_destroy_device(session->hid); hid_destroy_device(session->hid);
session->hid = NULL; session->hid = NULL;
atomic_inc(&session->terminate); kthread_stop(session->task);
hidp_schedule(session);
unlink: unlink:
hidp_del_timer(session); hidp_del_timer(session);
...@@ -1105,13 +1109,7 @@ int hidp_del_connection(struct hidp_conndel_req *req) ...@@ -1105,13 +1109,7 @@ int hidp_del_connection(struct hidp_conndel_req *req)
skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->ctrl_transmit);
skb_queue_purge(&session->intr_transmit); skb_queue_purge(&session->intr_transmit);
/* Wakeup user-space polling for socket errors */ kthread_stop(session->task);
session->intr_sock->sk->sk_err = EUNATCH;
session->ctrl_sock->sk->sk_err = EUNATCH;
/* Kill session thread */
atomic_inc(&session->terminate);
hidp_schedule(session);
} }
} else } else
err = -ENOENT; err = -ENOENT;
......
...@@ -84,8 +84,8 @@ ...@@ -84,8 +84,8 @@
#define HIDP_WAITING_FOR_SEND_ACK 11 #define HIDP_WAITING_FOR_SEND_ACK 11
struct hidp_connadd_req { struct hidp_connadd_req {
int ctrl_sock; // Connected control socket int ctrl_sock; /* Connected control socket */
int intr_sock; // Connteted interrupt socket int intr_sock; /* Connected interrupt socket */
__u16 parser; __u16 parser;
__u16 rd_size; __u16 rd_size;
__u8 __user *rd_data; __u8 __user *rd_data;
...@@ -142,7 +142,7 @@ struct hidp_session { ...@@ -142,7 +142,7 @@ struct hidp_session {
uint ctrl_mtu; uint ctrl_mtu;
uint intr_mtu; uint intr_mtu;
atomic_t terminate; struct task_struct *task;
unsigned char keys[8]; unsigned char keys[8];
unsigned char leds; unsigned char leds;
......
...@@ -85,7 +85,8 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long ...@@ -85,7 +85,8 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
return err; return err;
} }
if (csock->sk->sk_state != BT_CONNECTED || isock->sk->sk_state != BT_CONNECTED) { if (csock->sk->sk_state != BT_CONNECTED ||
isock->sk->sk_state != BT_CONNECTED) {
sockfd_put(csock); sockfd_put(csock);
sockfd_put(isock); sockfd_put(isock);
return -EBADFD; return -EBADFD;
...@@ -140,8 +141,8 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long ...@@ -140,8 +141,8 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
struct compat_hidp_connadd_req { struct compat_hidp_connadd_req {
int ctrl_sock; // Connected control socket int ctrl_sock; /* Connected control socket */
int intr_sock; // Connteted interrupt socket int intr_sock; /* Connected interrupt socket */
__u16 parser; __u16 parser;
__u16 rd_size; __u16 rd_size;
compat_uptr_t rd_data; compat_uptr_t rd_data;
......
...@@ -169,7 +169,7 @@ static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) ...@@ -169,7 +169,7 @@ static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
__sock_put(sk); __sock_put(sk);
} }
static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk)
{ {
struct l2cap_chan_list *l = &conn->chan_list; struct l2cap_chan_list *l = &conn->chan_list;
...@@ -204,9 +204,6 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so ...@@ -204,9 +204,6 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
} }
__l2cap_chan_link(l, sk); __l2cap_chan_link(l, sk);
if (parent)
bt_accept_enqueue(parent, sk);
} }
/* Delete channel. /* Delete channel.
...@@ -652,7 +649,9 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) ...@@ -652,7 +649,9 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
bacpy(&bt_sk(sk)->src, conn->src); bacpy(&bt_sk(sk)->src, conn->src);
bacpy(&bt_sk(sk)->dst, conn->dst); bacpy(&bt_sk(sk)->dst, conn->dst);
__l2cap_chan_add(conn, sk, parent); bt_accept_enqueue(parent, sk);
__l2cap_chan_add(conn, sk);
l2cap_sock_set_timer(sk, sk->sk_sndtimeo); l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
...@@ -793,11 +792,11 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) ...@@ -793,11 +792,11 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
kfree(conn); kfree(conn);
} }
static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk)
{ {
struct l2cap_chan_list *l = &conn->chan_list; struct l2cap_chan_list *l = &conn->chan_list;
write_lock_bh(&l->lock); write_lock_bh(&l->lock);
__l2cap_chan_add(conn, sk, parent); __l2cap_chan_add(conn, sk);
write_unlock_bh(&l->lock); write_unlock_bh(&l->lock);
} }
...@@ -876,7 +875,7 @@ int l2cap_do_connect(struct sock *sk) ...@@ -876,7 +875,7 @@ int l2cap_do_connect(struct sock *sk)
/* Update source addr of the socket */ /* Update source addr of the socket */
bacpy(src, conn->src); bacpy(src, conn->src);
l2cap_chan_add(conn, sk, NULL); l2cap_chan_add(conn, sk);
sk->sk_state = BT_CONNECT; sk->sk_state = BT_CONNECT;
l2cap_sock_set_timer(sk, sk->sk_sndtimeo); l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
...@@ -1116,7 +1115,9 @@ int l2cap_ertm_send(struct sock *sk) ...@@ -1116,7 +1115,9 @@ int l2cap_ertm_send(struct sock *sk)
bt_cb(skb)->tx_seq = pi->next_tx_seq; bt_cb(skb)->tx_seq = pi->next_tx_seq;
pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; pi->next_tx_seq = (pi->next_tx_seq + 1) % 64;
pi->unacked_frames++; if (bt_cb(skb)->retries == 1)
pi->unacked_frames++;
pi->frames_sent++; pi->frames_sent++;
if (skb_queue_is_last(TX_QUEUE(sk), skb)) if (skb_queue_is_last(TX_QUEUE(sk), skb))
...@@ -2030,7 +2031,9 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd ...@@ -2030,7 +2031,9 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
l2cap_pi(sk)->psm = psm; l2cap_pi(sk)->psm = psm;
l2cap_pi(sk)->dcid = scid; l2cap_pi(sk)->dcid = scid;
__l2cap_chan_add(conn, sk, parent); bt_accept_enqueue(parent, sk);
__l2cap_chan_add(conn, sk);
dcid = l2cap_pi(sk)->scid; dcid = l2cap_pi(sk)->scid;
l2cap_sock_set_timer(sk, sk->sk_sndtimeo); l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
...@@ -2460,6 +2463,11 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm ...@@ -2460,6 +2463,11 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
BT_DBG("type 0x%4.4x result 0x%2.2x", type, result); BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
/* L2CAP Info req/rsp are unbound to channels, add extra checks */
if (cmd->ident != conn->info_ident ||
conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
return 0;
del_timer(&conn->info_timer); del_timer(&conn->info_timer);
if (result != L2CAP_IR_SUCCESS) { if (result != L2CAP_IR_SUCCESS) {
...@@ -2670,7 +2678,8 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, ...@@ -2670,7 +2678,8 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
if (err) { if (err) {
struct l2cap_cmd_rej rej; struct l2cap_cmd_rej rej;
BT_DBG("error %d", err);
BT_ERR("Wrong link type (%d)", err);
/* FIXME: Map err to a valid reason */ /* FIXME: Map err to a valid reason */
rej.reason = cpu_to_le16(0); rej.reason = cpu_to_le16(0);
......
...@@ -923,8 +923,9 @@ void __l2cap_sock_close(struct sock *sk, int reason) ...@@ -923,8 +923,9 @@ void __l2cap_sock_close(struct sock *sk, int reason)
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
l2cap_send_cmd(conn, l2cap_pi(sk)->ident, l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp); L2CAP_CONN_RSP, sizeof(rsp), &rsp);
} else }
l2cap_chan_del(sk, reason);
l2cap_chan_del(sk, reason);
break; break;
case BT_CONNECT: case BT_CONNECT:
......
This diff is collapsed.
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