Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next-2.6

This commit is contained in:
John W. Linville 2011-04-07 15:30:53 -04:00
commit f3b3e36f4e
21 changed files with 971 additions and 281 deletions

View File

@ -71,6 +71,9 @@ static struct usb_device_id btusb_table[] = {
/* Apple MacBookAir3,1, MacBookAir3,2 */
{ USB_DEVICE(0x05ac, 0x821b) },
/* Apple MacBookPro8,2 */
{ USB_DEVICE(0x05ac, 0x821a) },
/* AVM BlueFRITZ! USB v2.0 */
{ USB_DEVICE(0x057c, 0x3800) },
@ -690,7 +693,8 @@ static int btusb_send_frame(struct sk_buff *skb)
break;
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;
urb = usb_alloc_urb(0, GFP_ATOMIC);

View File

@ -84,6 +84,8 @@ enum {
HCI_SERVICE_CACHE,
HCI_LINK_KEYS,
HCI_DEBUG_KEYS,
HCI_RESET,
};
/* HCI ioctl defines */
@ -426,6 +428,18 @@ struct hci_rp_user_confirm_reply {
#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
struct hci_cp_io_capability_neg_reply {
bdaddr_t bdaddr;
@ -535,15 +549,17 @@ struct hci_cp_delete_stored_link_key {
__u8 delete_all;
} __packed;
#define HCI_MAX_NAME_LENGTH 248
#define HCI_OP_WRITE_LOCAL_NAME 0x0c13
struct hci_cp_write_local_name {
__u8 name[248];
__u8 name[HCI_MAX_NAME_LENGTH];
} __packed;
#define HCI_OP_READ_LOCAL_NAME 0x0c14
struct hci_rp_read_local_name {
__u8 status;
__u8 name[248];
__u8 name[HCI_MAX_NAME_LENGTH];
} __packed;
#define HCI_OP_WRITE_CA_TIMEOUT 0x0c16
@ -600,6 +616,14 @@ struct hci_cp_host_buffer_size {
#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
struct hci_rp_read_ssp_mode {
__u8 status;
@ -611,6 +635,13 @@ struct hci_cp_write_ssp_mode {
__u8 mode;
} __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_LOCAL_VERSION 0x1001
@ -745,7 +776,7 @@ struct hci_ev_auth_complete {
struct hci_ev_remote_name {
__u8 status;
bdaddr_t bdaddr;
__u8 name[248];
__u8 name[HCI_MAX_NAME_LENGTH];
} __packed;
#define HCI_EV_ENCRYPT_CHANGE 0x08
@ -953,6 +984,11 @@ struct hci_ev_user_confirm_req {
__le32 passkey;
} __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
struct hci_ev_simple_pair_complete {
__u8 status;

View File

@ -82,6 +82,13 @@ struct link_key {
u8 pin_len;
};
struct oob_data {
struct list_head list;
bdaddr_t bdaddr;
u8 hash[16];
u8 randomizer[16];
};
#define NUM_REASSEMBLY 4
struct hci_dev {
struct list_head list;
@ -94,7 +101,8 @@ struct hci_dev {
__u8 bus;
__u8 dev_type;
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 major_class;
__u8 minor_class;
@ -169,6 +177,8 @@ struct hci_dev {
struct list_head link_keys;
struct list_head remote_oob_data;
struct hci_dev_stats stat;
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,
u8 *key, u8 type, u8 pin_len);
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_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);
int mgmt_user_confirm_neg_reply_complete(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 */
#define hci_pi(sk) ((struct hci_pinfo *) sk)

View File

@ -280,7 +280,6 @@ struct l2cap_conn_param_update_rsp {
struct l2cap_chan_list {
struct sock *head;
rwlock_t lock;
long num;
};
struct l2cap_conn {
@ -302,7 +301,6 @@ struct l2cap_conn {
struct sk_buff *rx_skb;
__u32 rx_len;
__u8 rx_ident;
__u8 tx_ident;
__u8 disc_reason;

View File

@ -41,6 +41,10 @@ struct mgmt_rp_read_index_list {
__le16 index[0];
} __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
struct mgmt_rp_read_info {
__u8 type;
@ -55,6 +59,7 @@ struct mgmt_rp_read_info {
__u16 manufacturer;
__u8 hci_ver;
__u16 hci_rev;
__u8 name[MGMT_MAX_NAME_LENGTH];
} __packed;
struct mgmt_mode {
@ -167,6 +172,29 @@ struct mgmt_rp_user_confirm_reply {
#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
struct mgmt_ev_cmd_complete {
__le16 opcode;
@ -234,3 +262,22 @@ struct mgmt_ev_auth_failed {
bdaddr_t bdaddr;
__u8 status;
} __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;

View File

@ -23,88 +23,88 @@
#include <linux/crc32.h>
#include <net/bluetooth/bluetooth.h>
// Limits
#define BNEP_MAX_PROTO_FILTERS 5
#define BNEP_MAX_MULTICAST_FILTERS 20
/* Limits */
#define BNEP_MAX_PROTO_FILTERS 5
#define BNEP_MAX_MULTICAST_FILTERS 20
// UUIDs
#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
#define BNEP_UUID16 0x02
#define BNEP_UUID32 0x04
#define BNEP_UUID128 0x16
/* UUIDs */
#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
#define BNEP_UUID16 0x02
#define BNEP_UUID32 0x04
#define BNEP_UUID128 0x16
#define BNEP_SVC_PANU 0x1115
#define BNEP_SVC_NAP 0x1116
#define BNEP_SVC_GN 0x1117
#define BNEP_SVC_PANU 0x1115
#define BNEP_SVC_NAP 0x1116
#define BNEP_SVC_GN 0x1117
// Packet types
#define BNEP_GENERAL 0x00
#define BNEP_CONTROL 0x01
#define BNEP_COMPRESSED 0x02
#define BNEP_COMPRESSED_SRC_ONLY 0x03
#define BNEP_COMPRESSED_DST_ONLY 0x04
/* Packet types */
#define BNEP_GENERAL 0x00
#define BNEP_CONTROL 0x01
#define BNEP_COMPRESSED 0x02
#define BNEP_COMPRESSED_SRC_ONLY 0x03
#define BNEP_COMPRESSED_DST_ONLY 0x04
// Control types
#define BNEP_CMD_NOT_UNDERSTOOD 0x00
#define BNEP_SETUP_CONN_REQ 0x01
#define BNEP_SETUP_CONN_RSP 0x02
#define BNEP_FILTER_NET_TYPE_SET 0x03
#define BNEP_FILTER_NET_TYPE_RSP 0x04
#define BNEP_FILTER_MULTI_ADDR_SET 0x05
#define BNEP_FILTER_MULTI_ADDR_RSP 0x06
/* Control types */
#define BNEP_CMD_NOT_UNDERSTOOD 0x00
#define BNEP_SETUP_CONN_REQ 0x01
#define BNEP_SETUP_CONN_RSP 0x02
#define BNEP_FILTER_NET_TYPE_SET 0x03
#define BNEP_FILTER_NET_TYPE_RSP 0x04
#define BNEP_FILTER_MULTI_ADDR_SET 0x05
#define BNEP_FILTER_MULTI_ADDR_RSP 0x06
// Extension types
#define BNEP_EXT_CONTROL 0x00
/* Extension types */
#define BNEP_EXT_CONTROL 0x00
// Response messages
#define BNEP_SUCCESS 0x00
/* Response messages */
#define BNEP_SUCCESS 0x00
#define BNEP_CONN_INVALID_DST 0x01
#define BNEP_CONN_INVALID_SRC 0x02
#define BNEP_CONN_INVALID_SVC 0x03
#define BNEP_CONN_NOT_ALLOWED 0x04
#define BNEP_CONN_INVALID_DST 0x01
#define BNEP_CONN_INVALID_SRC 0x02
#define BNEP_CONN_INVALID_SVC 0x03
#define BNEP_CONN_NOT_ALLOWED 0x04
#define BNEP_FILTER_UNSUPPORTED_REQ 0x01
#define BNEP_FILTER_INVALID_RANGE 0x02
#define BNEP_FILTER_INVALID_MCADDR 0x02
#define BNEP_FILTER_LIMIT_REACHED 0x03
#define BNEP_FILTER_DENIED_SECURITY 0x04
#define BNEP_FILTER_UNSUPPORTED_REQ 0x01
#define BNEP_FILTER_INVALID_RANGE 0x02
#define BNEP_FILTER_INVALID_MCADDR 0x02
#define BNEP_FILTER_LIMIT_REACHED 0x03
#define BNEP_FILTER_DENIED_SECURITY 0x04
// L2CAP settings
#define BNEP_MTU 1691
#define BNEP_PSM 0x0f
#define BNEP_FLUSH_TO 0xffff
#define BNEP_CONNECT_TO 15
#define BNEP_FILTER_TO 15
/* L2CAP settings */
#define BNEP_MTU 1691
#define BNEP_PSM 0x0f
#define BNEP_FLUSH_TO 0xffff
#define BNEP_CONNECT_TO 15
#define BNEP_FILTER_TO 15
// Headers
#define BNEP_TYPE_MASK 0x7f
#define BNEP_EXT_HEADER 0x80
/* Headers */
#define BNEP_TYPE_MASK 0x7f
#define BNEP_EXT_HEADER 0x80
struct bnep_setup_conn_req {
__u8 type;
__u8 ctrl;
__u8 uuid_size;
__u8 service[0];
__u8 type;
__u8 ctrl;
__u8 uuid_size;
__u8 service[0];
} __packed;
struct bnep_set_filter_req {
__u8 type;
__u8 ctrl;
__u8 type;
__u8 ctrl;
__be16 len;
__u8 list[0];
__u8 list[0];
} __packed;
struct bnep_control_rsp {
__u8 type;
__u8 ctrl;
__u8 type;
__u8 ctrl;
__be16 resp;
} __packed;
struct bnep_ext_hdr {
__u8 type;
__u8 len;
__u8 data[0];
__u8 type;
__u8 len;
__u8 data[0];
} __packed;
/* BNEP ioctl defines */
@ -114,10 +114,10 @@ struct bnep_ext_hdr {
#define BNEPGETCONNINFO _IOR('B', 211, int)
struct bnep_connadd_req {
int sock; // Connected socket
int sock; /* Connected socket */
__u32 flags;
__u16 role;
char device[16]; // Name of the Ethernet device
char device[16]; /* Name of the Ethernet device */
};
struct bnep_conndel_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_conninfo(struct bnep_conninfo *ci);
// BNEP sessions
/* BNEP sessions */
struct bnep_session {
struct list_head list;
unsigned int role;
unsigned long state;
unsigned long flags;
atomic_t killed;
struct task_struct *task;
struct ethhdr eh;
struct msghdr msg;
@ -173,7 +173,7 @@ void bnep_sock_cleanup(void);
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

View File

@ -36,6 +36,7 @@
#include <linux/errno.h>
#include <linux/net.h>
#include <linux/slab.h>
#include <linux/kthread.h>
#include <net/sock.h>
#include <linux/socket.h>
@ -131,7 +132,8 @@ static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len
return -EILSEQ;
n = get_unaligned_be16(data);
data++; len -= 2;
data++;
len -= 2;
if (len < n)
return -EILSEQ;
@ -176,7 +178,8 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
return -EILSEQ;
n = get_unaligned_be16(data);
data += 2; len -= 2;
data += 2;
len -= 2;
if (len < n)
return -EILSEQ;
@ -187,6 +190,8 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
n /= (ETH_ALEN * 2);
if (n > 0) {
int i;
s->mc_filter = 0;
/* Always send broadcast */
@ -196,18 +201,22 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
for (; n > 0; n--) {
u8 a1[6], *a2;
memcpy(a1, data, ETH_ALEN); data += ETH_ALEN;
a2 = data; data += ETH_ALEN;
memcpy(a1, data, ETH_ALEN);
data += ETH_ALEN;
a2 = data;
data += ETH_ALEN;
BT_DBG("mc filter %s -> %s",
batostr((void *) a1), batostr((void *) a2));
#define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); }
/* Iterate from a1 to a2 */
set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
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);
}
}
@ -227,7 +236,8 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len)
u8 cmd = *(u8 *)data;
int err = 0;
data++; len--;
data++;
len--;
switch (cmd) {
case BNEP_CMD_NOT_UNDERSTOOD:
@ -302,7 +312,6 @@ static u8 __bnep_rx_hlen[] = {
ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_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)
{
@ -312,9 +321,10 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
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;
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)
case BNEP_COMPRESSED_DST_ONLY:
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,
ETH_ALEN + 2);
ETH_ALEN + 2);
break;
case BNEP_GENERAL:
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));
break;
}
@ -470,15 +480,14 @@ static int bnep_session(void *arg)
BT_DBG("");
daemonize("kbnepd %s", dev->name);
set_user_nice(current, -15);
init_waitqueue_entry(&wait, current);
add_wait_queue(sk_sleep(sk), &wait);
while (!atomic_read(&s->killed)) {
while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
// RX
/* RX */
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb);
bnep_rx_frame(s, skb);
@ -487,7 +496,7 @@ static int bnep_session(void *arg)
if (sk->sk_state != BT_CONNECTED)
break;
// TX
/* TX */
while ((skb = skb_dequeue(&sk->sk_write_queue)))
if (bnep_tx_frame(s, skb))
break;
@ -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 */
dev = alloc_netdev(sizeof(struct bnep_session),
(*req->device) ? req->device : "bnep%d",
bnep_net_setup);
(*req->device) ? req->device : "bnep%d",
bnep_net_setup);
if (!dev)
return -ENOMEM;
@ -571,7 +580,7 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
s = netdev_priv(dev);
/* 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_source, &dst, 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)
SET_NETDEV_DEVTYPE(dev, &bnep_type);
err = register_netdev(dev);
if (err) {
if (err)
goto failed;
}
__bnep_link_session(s);
err = kernel_thread(bnep_session, s, CLONE_KERNEL);
if (err < 0) {
s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
if (IS_ERR(s->task)) {
/* Session thread start failed, gotta cleanup. */
unregister_netdev(dev);
__bnep_unlink_session(s);
err = PTR_ERR(s->task);
goto failed;
}
@ -631,15 +640,9 @@ int bnep_del_connection(struct bnep_conndel_req *req)
down_read(&bnep_session_sem);
s = __bnep_get_session(req->dst);
if (s) {
/* Wakeup user-space which is polling for socket errors.
* This is temporary hack until we have shutdown in L2CAP */
s->sock->sk->sk_err = EUNATCH;
/* Kill session thread */
atomic_inc(&s->killed);
wake_up_interruptible(sk_sleep(s->sock->sk));
} else
if (s)
kthread_stop(s->task);
else
err = -ENOENT;
up_read(&bnep_session_sem);

View File

@ -39,10 +39,10 @@
#include <linux/init.h>
#include <linux/compat.h>
#include <linux/gfp.h>
#include <linux/uaccess.h>
#include <net/sock.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include "bnep.h"

View File

@ -35,6 +35,7 @@
#include <linux/ioctl.h>
#include <linux/file.h>
#include <linux/wait.h>
#include <linux/kthread.h>
#include <net/sock.h>
#include <linux/isdn/capilli.h>
@ -143,7 +144,7 @@ static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *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,
@ -386,8 +387,7 @@ static void cmtp_reset_ctr(struct capi_ctr *ctrl)
capi_ctr_down(ctrl);
atomic_inc(&session->terminate);
cmtp_schedule(session);
kthread_stop(session->task);
}
static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)

View File

@ -37,7 +37,7 @@
#define CMTP_LOOPBACK 0
struct cmtp_connadd_req {
int sock; // Connected socket
int sock; /* Connected socket */
__u32 flags;
};
@ -81,7 +81,7 @@ struct cmtp_session {
char name[BTNAMSIZ];
atomic_t terminate;
struct task_struct *task;
wait_queue_head_t wait;
@ -121,13 +121,6 @@ void cmtp_detach_device(struct cmtp_session *session);
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 */
int cmtp_init_sockets(void);
void cmtp_cleanup_sockets(void);

View File

@ -35,6 +35,7 @@
#include <linux/ioctl.h>
#include <linux/file.h>
#include <linux/init.h>
#include <linux/kthread.h>
#include <net/sock.h>
#include <linux/isdn/capilli.h>
@ -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);
if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) {
skb_queue_head(&session->transmit, skb);
break;
if (scb->id < 0) {
scb->id = cmtp_alloc_block_id(session);
if (scb->id < 0) {
skb_queue_head(&session->transmit, skb);
break;
}
}
if (size < 256) {
@ -284,12 +288,11 @@ static int cmtp_session(void *arg)
BT_DBG("session %p", session);
daemonize("kcmtpd_ctr_%d", session->num);
set_user_nice(current, -15);
init_waitqueue_entry(&wait, current);
add_wait_queue(sk_sleep(sk), &wait);
while (!atomic_read(&session->terminate)) {
while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
if (sk->sk_state != BT_CONNECTED)
@ -367,9 +370,12 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
__cmtp_link_session(session);
err = kernel_thread(cmtp_session, session, CLONE_KERNEL);
if (err < 0)
session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d",
session->num);
if (IS_ERR(session->task)) {
err = PTR_ERR(session->task);
goto unlink;
}
if (!(session->flags & (1 << CMTP_LOOPBACK))) {
err = cmtp_attach_device(session);
@ -406,9 +412,8 @@ int cmtp_del_connection(struct cmtp_conndel_req *req)
/* Flush the transmit queue */
skb_queue_purge(&session->transmit);
/* Kill session thread */
atomic_inc(&session->terminate);
cmtp_schedule(session);
/* Stop session thread */
kthread_stop(session->task);
} else
err = -ENOENT;

View File

@ -34,12 +34,12 @@
#include <linux/file.h>
#include <linux/compat.h>
#include <linux/gfp.h>
#include <linux/uaccess.h>
#include <net/sock.h>
#include <linux/isdn/capilli.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include "cmtp.h"

View File

@ -56,7 +56,6 @@
static void hci_cmd_task(unsigned long arg);
static void hci_rx_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);
@ -186,6 +185,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
BT_DBG("%s %ld", hdev->name, opt);
/* Reset device */
set_bit(HCI_RESET, &hdev->flags);
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)
/* Mandatory initialization */
/* 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);
}
/* Read Local Supported Features */
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)
hci_req_cancel(hdev, ENODEV);
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)) {
hci_req_unlock(hdev);
return 0;
@ -623,7 +628,6 @@ static int hci_dev_do_close(struct hci_dev *hdev)
/* Drop last sent command */
if (hdev->sent_cmd) {
del_timer_sync(&hdev->cmd_timer);
kfree_skb(hdev->sent_cmd);
hdev->sent_cmd = NULL;
}
@ -1074,9 +1078,74 @@ static void hci_cmd_timer(unsigned long arg)
BT_ERR("%s command tx timeout", hdev->name);
atomic_set(&hdev->cmd_cnt, 1);
clear_bit(HCI_RESET, &hdev->flags);
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 */
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->remote_oob_data);
INIT_WORK(&hdev->power_on, hci_power_on);
INIT_WORK(&hdev->power_off, hci_power_off);
setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
@ -1220,6 +1291,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_blacklist_clear(hdev);
hci_uuids_clear(hdev);
hci_link_keys_clear(hdev);
hci_remote_oob_data_clear(hdev);
hci_dev_unlock_bh(hdev);
__hci_dev_put(hdev);
@ -1269,7 +1341,7 @@ int hci_recv_frame(struct sk_buff *skb)
EXPORT_SYMBOL(hci_recv_frame);
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 hlen = 0;
@ -1299,7 +1371,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
break;
}
skb = bt_skb_alloc(len, gfp_mask);
skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
@ -1385,8 +1457,7 @@ int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
return -EILSEQ;
while (count) {
rem = hci_reassembly(hdev, type, data, count,
type - 1, GFP_ATOMIC);
rem = hci_reassembly(hdev, type, data, count, type - 1);
if (rem < 0)
return rem;
@ -1420,8 +1491,8 @@ int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
} else
type = bt_cb(skb)->pkt_type;
rem = hci_reassembly(hdev, type, data,
count, STREAM_REASSEMBLY, GFP_ATOMIC);
rem = hci_reassembly(hdev, type, data, count,
STREAM_REASSEMBLY);
if (rem < 0)
return rem;

View File

@ -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);
clear_bit(HCI_RESET, &hdev->flags);
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)
BT_DBG("%s status 0x%x", hdev->name, status);
if (status)
return;
sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
if (!sent)
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)
@ -212,7 +217,7 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
if (rp->status)
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)
@ -819,6 +824,17 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
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)
{
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 *
hci_dev_lock(hdev);
for (; num_rsp; num_rsp--) {
for (; num_rsp; num_rsp--, info++) {
bacpy(&data.bdaddr, &info->bdaddr);
data.pscan_rep_mode = info->pscan_rep_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 *
data.clock_offset = info->clock_offset;
data.rssi = 0x00;
data.ssp_mode = 0x00;
info++;
hci_inquiry_cache_update(hdev, &data);
mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, 0,
NULL);
}
hci_dev_unlock(hdev);
@ -1480,6 +1497,9 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb
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);
if (conn && hci_outgoing_auth_needed(hdev, conn)) {
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
hci_cc_pin_code_neg_reply(hdev, skb);
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:
hci_cc_le_read_buffer_size(hdev, skb);
break;
@ -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)
del_timer(&hdev->cmd_timer);
if (ev->ncmd) {
if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q))
tasklet_schedule(&hdev->cmd_task);
@ -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;
info = (void *) (skb->data + 1);
for (; num_rsp; num_rsp--) {
for (; num_rsp; num_rsp--, info++) {
bacpy(&data.bdaddr, &info->bdaddr);
data.pscan_rep_mode = info->pscan_rep_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
data.clock_offset = info->clock_offset;
data.rssi = info->rssi;
data.ssp_mode = 0x00;
info++;
hci_inquiry_cache_update(hdev, &data);
mgmt_device_found(hdev->id, &info->bdaddr,
info->dev_class, info->rssi,
NULL);
}
} else {
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);
data.pscan_rep_mode = info->pscan_rep_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
data.clock_offset = info->clock_offset;
data.rssi = info->rssi;
data.ssp_mode = 0x00;
info++;
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
hci_dev_lock(hdev);
for (; num_rsp; num_rsp--) {
for (; num_rsp; num_rsp--, info++) {
bacpy(&data.bdaddr, &info->bdaddr);
data.pscan_rep_mode = info->pscan_rep_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
data.clock_offset = info->clock_offset;
data.rssi = info->rssi;
data.ssp_mode = 0x01;
info++;
hci_inquiry_cache_update(hdev, &data);
mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class,
info->rssi, info->data);
}
hci_dev_unlock(hdev);
@ -2353,9 +2382,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
bacpy(&cp.bdaddr, &ev->bdaddr);
cp.capability = conn->io_capability;
cp.oob_data = 0;
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,
sizeof(cp), &cp);
} else {
@ -2453,6 +2487,37 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
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)
{
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)
hci_le_meta_evt(hdev, skb);
break;
case HCI_EV_REMOTE_OOB_DATA_REQUEST:
hci_remote_oob_data_request_evt(hdev, skb);
break;
default:
BT_DBG("%s event 0x%x", hdev->name, event);
break;

View File

@ -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)
{
struct hci_dev *hdev = dev_get_drvdata(dev);
char name[249];
char name[HCI_MAX_NAME_LENGTH + 1];
int i;
for (i = 0; i < 248; i++)
for (i = 0; i < HCI_MAX_NAME_LENGTH; i++)
name[i] = hdev->dev_name[i];
name[248] = '\0';
name[HCI_MAX_NAME_LENGTH] = '\0';
return sprintf(buf, "%s\n", name);
}
@ -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)
{
struct hci_dev *hdev = dev_get_drvdata(dev);
unsigned long val;
unsigned int val;
int rv;
if (strict_strtoul(buf, 0, &val) < 0)
return -EINVAL;
rv = kstrtouint(buf, 0, &val);
if (rv < 0)
return rv;
if (val != 0 && (val < 500 || val > 3600000))
return -EINVAL;
@ -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)
{
struct hci_dev *hdev = dev_get_drvdata(dev);
unsigned long val;
u16 val;
int rv;
if (strict_strtoul(buf, 0, &val) < 0)
return -EINVAL;
rv = kstrtou16(buf, 0, &val);
if (rv < 0)
return rv;
if (val < 0x0002 || val > 0xFFFE || val % 2)
return -EINVAL;
if (val < hdev->sniff_min_interval)
if (val == 0 || val % 2 || val < hdev->sniff_min_interval)
return -EINVAL;
hdev->sniff_max_interval = val;
@ -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)
{
struct hci_dev *hdev = dev_get_drvdata(dev);
unsigned long val;
u16 val;
int rv;
if (strict_strtoul(buf, 0, &val) < 0)
return -EINVAL;
rv = kstrtou16(buf, 0, &val);
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;
hdev->sniff_min_interval = val;

View File

@ -37,6 +37,7 @@
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/mutex.h>
#include <linux/kthread.h>
#include <net/sock.h>
#include <linux/input.h>
@ -55,22 +56,24 @@ static DECLARE_RWSEM(hidp_session_sem);
static LIST_HEAD(hidp_session_list);
static unsigned char hidp_keycode[256] = {
0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 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,
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
0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36,
37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45,
21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1,
14, 15, 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52,
53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88,
99, 70, 119, 110, 102, 104, 111, 107, 109, 106, 105, 108, 103, 69,
98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73,
82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190,
191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135,
136, 113, 115, 114, 0, 0, 0, 121, 0, 89, 93, 124, 92, 94,
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,
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 };
@ -461,8 +464,7 @@ static void hidp_idle_timeout(unsigned long arg)
{
struct hidp_session *session = (struct hidp_session *) arg;
atomic_inc(&session->terminate);
hidp_schedule(session);
kthread_stop(session->task);
}
static void hidp_set_timer(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->intr_transmit);
/* Kill session thread */
atomic_inc(&session->terminate);
hidp_schedule(session);
kthread_stop(session->task);
}
}
@ -694,22 +694,10 @@ static int hidp_session(void *arg)
struct sock *ctrl_sk = session->ctrl_sock->sk;
struct sock *intr_sk = session->intr_sock->sk;
struct sk_buff *skb;
int vendor = 0x0000, product = 0x0000;
wait_queue_t ctrl_wait, intr_wait;
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);
init_waitqueue_entry(&ctrl_wait, current);
@ -718,10 +706,11 @@ static int hidp_session(void *arg)
add_wait_queue(sk_sleep(intr_sk), &intr_wait);
session->waiting_for_startup = 0;
wake_up_interruptible(&session->startup_queue);
while (!atomic_read(&session->terminate)) {
while (!kthread_should_stop()) {
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;
while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
@ -965,6 +954,7 @@ fault:
int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
{
struct hidp_session *session, *s;
int vendor, product;
int err;
BT_DBG("");
@ -1026,9 +1016,24 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
hidp_set_timer(session);
err = kernel_thread(hidp_session, session, CLONE_KERNEL);
if (err < 0)
if (session->hid) {
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;
}
while (session->waiting_for_startup) {
wait_event_interruptible(session->startup_queue,
!session->waiting_for_startup);
@ -1053,8 +1058,7 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
err_add_device:
hid_destroy_device(session->hid);
session->hid = NULL;
atomic_inc(&session->terminate);
hidp_schedule(session);
kthread_stop(session->task);
unlink:
hidp_del_timer(session);
@ -1105,13 +1109,7 @@ int hidp_del_connection(struct hidp_conndel_req *req)
skb_queue_purge(&session->ctrl_transmit);
skb_queue_purge(&session->intr_transmit);
/* Wakeup user-space polling for socket errors */
session->intr_sock->sk->sk_err = EUNATCH;
session->ctrl_sock->sk->sk_err = EUNATCH;
/* Kill session thread */
atomic_inc(&session->terminate);
hidp_schedule(session);
kthread_stop(session->task);
}
} else
err = -ENOENT;

View File

@ -84,8 +84,8 @@
#define HIDP_WAITING_FOR_SEND_ACK 11
struct hidp_connadd_req {
int ctrl_sock; // Connected control socket
int intr_sock; // Connteted interrupt socket
int ctrl_sock; /* Connected control socket */
int intr_sock; /* Connected interrupt socket */
__u16 parser;
__u16 rd_size;
__u8 __user *rd_data;
@ -142,7 +142,7 @@ struct hidp_session {
uint ctrl_mtu;
uint intr_mtu;
atomic_t terminate;
struct task_struct *task;
unsigned char keys[8];
unsigned char leds;

View File

@ -85,7 +85,8 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
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(isock);
return -EBADFD;
@ -140,8 +141,8 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
#ifdef CONFIG_COMPAT
struct compat_hidp_connadd_req {
int ctrl_sock; // Connected control socket
int intr_sock; // Connteted interrupt socket
int ctrl_sock; /* Connected control socket */
int intr_sock; /* Connected interrupt socket */
__u16 parser;
__u16 rd_size;
compat_uptr_t rd_data;

View File

@ -169,7 +169,7 @@ static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *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;
@ -204,9 +204,6 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
}
__l2cap_chan_link(l, sk);
if (parent)
bt_accept_enqueue(parent, sk);
}
/* Delete channel.
@ -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)->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);
@ -793,11 +792,11 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
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;
write_lock_bh(&l->lock);
__l2cap_chan_add(conn, sk, parent);
__l2cap_chan_add(conn, sk);
write_unlock_bh(&l->lock);
}
@ -876,7 +875,7 @@ int l2cap_do_connect(struct sock *sk)
/* Update source addr of the socket */
bacpy(src, conn->src);
l2cap_chan_add(conn, sk, NULL);
l2cap_chan_add(conn, sk);
sk->sk_state = BT_CONNECT;
l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
@ -1116,7 +1115,9 @@ int l2cap_ertm_send(struct sock *sk)
bt_cb(skb)->tx_seq = pi->next_tx_seq;
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++;
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
l2cap_pi(sk)->psm = psm;
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;
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
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);
if (result != L2CAP_IR_SUCCESS) {
@ -2670,7 +2678,8 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
if (err) {
struct l2cap_cmd_rej rej;
BT_DBG("error %d", err);
BT_ERR("Wrong link type (%d)", err);
/* FIXME: Map err to a valid reason */
rej.reason = cpu_to_le16(0);

View File

@ -923,8 +923,9 @@ void __l2cap_sock_close(struct sock *sk, int reason)
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
} else
l2cap_chan_del(sk, reason);
}
l2cap_chan_del(sk, reason);
break;
case BT_CONNECT:

View File

@ -36,7 +36,7 @@ struct pending_cmd {
struct list_head list;
__u16 opcode;
int index;
void *cmd;
void *param;
struct sock *sk;
void *user_data;
};
@ -179,10 +179,12 @@ static int read_controller_info(struct sock *sk, u16 index)
hci_del_off_timer(hdev);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
set_bit(HCI_MGMT, &hdev->flags);
memset(&rp, 0, sizeof(rp));
rp.type = hdev->dev_type;
rp.powered = test_bit(HCI_UP, &hdev->flags);
@ -204,7 +206,9 @@ static int read_controller_info(struct sock *sk, u16 index)
rp.hci_ver = hdev->hci_ver;
put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
hci_dev_unlock_bh(hdev);
memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
@ -213,7 +217,7 @@ static int read_controller_info(struct sock *sk, u16 index)
static void mgmt_pending_free(struct pending_cmd *cmd)
{
sock_put(cmd->sk);
kfree(cmd->cmd);
kfree(cmd->param);
kfree(cmd);
}
@ -229,13 +233,14 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
cmd->opcode = opcode;
cmd->index = index;
cmd->cmd = kmalloc(len, GFP_ATOMIC);
if (!cmd->cmd) {
cmd->param = kmalloc(len, GFP_ATOMIC);
if (!cmd->param) {
kfree(cmd);
return NULL;
}
memcpy(cmd->cmd, data, len);
if (data)
memcpy(cmd->param, data, len);
cmd->sk = sk;
sock_hold(sk);
@ -311,7 +316,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
up = test_bit(HCI_UP, &hdev->flags);
if ((cp->val && up) || (!cp->val && !up)) {
@ -338,7 +343,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
err = 0;
failed:
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
}
@ -363,7 +368,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
@ -398,7 +403,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
@ -424,7 +429,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
@ -458,7 +463,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
@ -517,7 +522,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
if (cp->val)
set_bit(HCI_PAIRABLE, &hdev->flags);
@ -533,12 +538,156 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
failed:
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
}
#define EIR_FLAGS 0x01 /* flags */
#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
#define EIR_NAME_SHORT 0x08 /* shortened local name */
#define EIR_NAME_COMPLETE 0x09 /* complete local name */
#define EIR_TX_POWER 0x0A /* transmit power level */
#define EIR_DEVICE_ID 0x10 /* device ID */
#define PNP_INFO_SVCLASS_ID 0x1200
static u8 bluetooth_base_uuid[] = {
0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static u16 get_uuid16(u8 *uuid128)
{
u32 val;
int i;
for (i = 0; i < 12; i++) {
if (bluetooth_base_uuid[i] != uuid128[i])
return 0;
}
memcpy(&val, &uuid128[12], 4);
val = le32_to_cpu(val);
if (val > 0xffff)
return 0;
return (u16) val;
}
static void create_eir(struct hci_dev *hdev, u8 *data)
{
u8 *ptr = data;
u16 eir_len = 0;
u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
int i, truncated = 0;
struct list_head *p;
size_t name_len;
name_len = strlen(hdev->dev_name);
if (name_len > 0) {
/* EIR Data type */
if (name_len > 48) {
name_len = 48;
ptr[1] = EIR_NAME_SHORT;
} else
ptr[1] = EIR_NAME_COMPLETE;
/* EIR Data length */
ptr[0] = name_len + 1;
memcpy(ptr + 2, hdev->dev_name, name_len);
eir_len += (name_len + 2);
ptr += (name_len + 2);
}
memset(uuid16_list, 0, sizeof(uuid16_list));
/* Group all UUID16 types */
list_for_each(p, &hdev->uuids) {
struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
u16 uuid16;
uuid16 = get_uuid16(uuid->uuid);
if (uuid16 == 0)
return;
if (uuid16 < 0x1100)
continue;
if (uuid16 == PNP_INFO_SVCLASS_ID)
continue;
/* Stop if not enough space to put next UUID */
if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
truncated = 1;
break;
}
/* Check for duplicates */
for (i = 0; uuid16_list[i] != 0; i++)
if (uuid16_list[i] == uuid16)
break;
if (uuid16_list[i] == 0) {
uuid16_list[i] = uuid16;
eir_len += sizeof(u16);
}
}
if (uuid16_list[0] != 0) {
u8 *length = ptr;
/* EIR Data type */
ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
ptr += 2;
eir_len += 2;
for (i = 0; uuid16_list[i] != 0; i++) {
*ptr++ = (uuid16_list[i] & 0x00ff);
*ptr++ = (uuid16_list[i] & 0xff00) >> 8;
}
/* EIR Data length */
*length = (i * sizeof(u16)) + 1;
}
}
static int update_eir(struct hci_dev *hdev)
{
struct hci_cp_write_eir cp;
if (!(hdev->features[6] & LMP_EXT_INQ))
return 0;
if (hdev->ssp_mode == 0)
return 0;
if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
return 0;
memset(&cp, 0, sizeof(cp));
create_eir(hdev, cp.data);
if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
return 0;
memcpy(hdev->eir, cp.data, sizeof(cp.data));
return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
}
static u8 get_service_classes(struct hci_dev *hdev)
{
struct list_head *p;
@ -590,7 +739,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (!hdev)
return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
if (!uuid) {
@ -607,10 +756,14 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (err < 0)
goto failed;
err = update_eir(hdev);
if (err < 0)
goto failed;
err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
failed:
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
@ -635,7 +788,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (!hdev)
return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
err = hci_uuids_clear(hdev);
@ -663,10 +816,14 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (err < 0)
goto unlock;
err = update_eir(hdev);
if (err < 0)
goto unlock;
err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
unlock:
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
@ -690,7 +847,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
hdev->major_class = cp->major;
hdev->minor_class = cp->minor;
@ -700,7 +857,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
if (err == 0)
err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
@ -722,7 +879,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
BT_DBG("hci%u enable %d", index, cp->enable);
@ -732,13 +889,15 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
} else {
clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
err = update_class(hdev);
if (err == 0)
err = update_eir(hdev);
}
if (err == 0)
err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
0);
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
@ -772,7 +931,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
key_count);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
hci_link_keys_clear(hdev);
@ -790,7 +949,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
key->pin_len);
}
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return 0;
@ -812,7 +971,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (!hdev)
return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
err = hci_remove_link_key(hdev, &cp->bdaddr);
if (err < 0) {
@ -835,7 +994,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
}
unlock:
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
@ -861,7 +1020,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (!hdev)
return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
@ -893,7 +1052,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
@ -914,7 +1073,7 @@ static int get_connections(struct sock *sk, u16 index)
if (!hdev)
return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
count = 0;
list_for_each(p, &hdev->conn_hash.list) {
@ -945,7 +1104,7 @@ static int get_connections(struct sock *sk, u16 index)
unlock:
kfree(rp);
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
}
@ -970,7 +1129,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
@ -992,7 +1151,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
@ -1019,7 +1178,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
ENODEV);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
@ -1040,7 +1199,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
@ -1063,14 +1222,14 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
hdev->io_capability = cp->io_capability;
BT_DBG("%s IO capability set to 0x%02x", hdev->name,
hdev->io_capability);
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
@ -1156,7 +1315,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (!hdev)
return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
hci_dev_lock_bh(hdev);
hci_dev_lock(hdev);
if (cp->io_cap == 0x03) {
sec_level = BT_SECURITY_MEDIUM;
@ -1198,7 +1357,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
err = 0;
unlock:
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
@ -1230,6 +1389,8 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
if (!hdev)
return cmd_status(sk, index, mgmt_op, ENODEV);
hci_dev_lock(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, mgmt_op, ENETDOWN);
goto failed;
@ -1246,7 +1407,163 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock_bh(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
}
static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
struct hci_cp_write_local_name hci_cp;
struct hci_dev *hdev;
struct pending_cmd *cmd;
int err;
BT_DBG("");
if (len != sizeof(*mgmt_cp))
return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
hdev = hci_dev_get(index);
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
hci_dev_lock(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
if (!cmd) {
err = -ENOMEM;
goto failed;
}
memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
&hci_cp);
if (err < 0)
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
}
static int read_local_oob_data(struct sock *sk, u16 index)
{
struct hci_dev *hdev;
struct pending_cmd *cmd;
int err;
BT_DBG("hci%u", index);
hdev = hci_dev_get(index);
if (!hdev)
return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
ENODEV);
hci_dev_lock(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
ENETDOWN);
goto unlock;
}
if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
EOPNOTSUPP);
goto unlock;
}
if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
goto unlock;
}
cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
if (!cmd) {
err = -ENOMEM;
goto unlock;
}
err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
if (err < 0)
mgmt_pending_remove(cmd);
unlock:
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
}
static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
struct hci_dev *hdev;
struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
int err;
BT_DBG("hci%u ", index);
if (len != sizeof(*cp))
return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
EINVAL);
hdev = hci_dev_get(index);
if (!hdev)
return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
ENODEV);
hci_dev_lock(hdev);
err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
cp->randomizer);
if (err < 0)
err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
else
err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
0);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
}
static int remove_remote_oob_data(struct sock *sk, u16 index,
unsigned char *data, u16 len)
{
struct hci_dev *hdev;
struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
int err;
BT_DBG("hci%u ", index);
if (len != sizeof(*cp))
return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
EINVAL);
hdev = hci_dev_get(index);
if (!hdev)
return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
ENODEV);
hci_dev_lock(hdev);
err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
if (err < 0)
err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
-err);
else
err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
NULL, 0);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
@ -1264,7 +1581,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
if (msglen < sizeof(*hdr))
return -EINVAL;
buf = kmalloc(msglen, GFP_ATOMIC);
buf = kmalloc(msglen, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@ -1347,6 +1664,20 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case MGMT_OP_USER_CONFIRM_NEG_REPLY:
err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
break;
case MGMT_OP_SET_LOCAL_NAME:
err = set_local_name(sk, index, buf + sizeof(*hdr), len);
break;
case MGMT_OP_READ_LOCAL_OOB_DATA:
err = read_local_oob_data(sk, index);
break;
case MGMT_OP_ADD_REMOTE_OOB_DATA:
err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
break;
case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
len);
break;
default:
BT_DBG("Unknown op %u", opcode);
err = cmd_status(sk, index, opcode, 0x01);
@ -1380,7 +1711,7 @@ struct cmd_lookup {
static void mode_rsp(struct pending_cmd *cmd, void *data)
{
struct mgmt_mode *cp = cmd->cmd;
struct mgmt_mode *cp = cmd->param;
struct cmd_lookup *match = data;
if (cp->val != match->val)
@ -1479,7 +1810,7 @@ int mgmt_connected(u16 index, bdaddr_t *bdaddr)
static void disconnect_rsp(struct pending_cmd *cmd, void *data)
{
struct mgmt_cp_disconnect *cp = cmd->cmd;
struct mgmt_cp_disconnect *cp = cmd->param;
struct sock **sk = data;
struct mgmt_rp_disconnect rp;
@ -1643,3 +1974,104 @@ int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
}
int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
{
struct pending_cmd *cmd;
struct hci_dev *hdev;
struct mgmt_cp_set_local_name ev;
int err;
memset(&ev, 0, sizeof(ev));
memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
if (!cmd)
goto send_event;
if (status) {
err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
goto failed;
}
hdev = hci_dev_get(index);
if (hdev) {
hci_dev_lock_bh(hdev);
update_eir(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
}
err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
sizeof(ev));
if (err < 0)
goto failed;
send_event:
err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
cmd ? cmd->sk : NULL);
failed:
if (cmd)
mgmt_pending_remove(cmd);
return err;
}
int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
u8 status)
{
struct pending_cmd *cmd;
int err;
BT_DBG("hci%u status %u", index, status);
cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
if (!cmd)
return -ENOENT;
if (status) {
err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
EIO);
} else {
struct mgmt_rp_read_local_oob_data rp;
memcpy(rp.hash, hash, sizeof(rp.hash));
memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
&rp, sizeof(rp));
}
mgmt_pending_remove(cmd);
return err;
}
int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
u8 *eir)
{
struct mgmt_ev_device_found ev;
memset(&ev, 0, sizeof(ev));
bacpy(&ev.bdaddr, bdaddr);
memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
ev.rssi = rssi;
if (eir)
memcpy(ev.eir, eir, sizeof(ev.eir));
return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
}
int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
{
struct mgmt_ev_remote_name ev;
memset(&ev, 0, sizeof(ev));
bacpy(&ev.bdaddr, bdaddr);
memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
}