Bluetooth: Backport BT manager 1.3
Backported from msm 3.10 kernel
Change-Id: I0c4ba93e9d590388efd562c3dbb3a2d1ac5f3c6a
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index fe5136d..326b193 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -171,6 +171,18 @@
return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
}
+/**
+ * ether_addr_equal - Compare two Ethernet addresses
+ * @addr1: Pointer to a six-byte array containing the Ethernet address
+ * @addr2: Pointer other six-byte array containing the Ethernet address
+ *
+ * Compare two Ethernet addresses, returns true if equal
+ */
+static inline bool ether_addr_equal(const u8 *addr1, const u8 *addr2)
+{
+ return !compare_ether_addr(addr1, addr2);
+}
+
static inline unsigned long zap_last_2bytes(unsigned long value)
{
#ifdef __BIG_ENDIAN
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 4f01897..0c6e4c9 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -723,6 +723,7 @@
extern int hid_debug;
+extern bool hid_ignore(struct hid_device *);
extern int hid_add_device(struct hid_device *);
extern void hid_destroy_device(struct hid_device *);
@@ -746,6 +747,7 @@
struct hid_field *hidinput_get_led_field(struct hid_device *hid);
unsigned int hidinput_count_leds(struct hid_device *hid);
void hid_output_report(struct hid_report *report, __u8 *data);
+u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
struct hid_device *hid_allocate_device(void);
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
int hid_open_report(struct hid_device *device);
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index 56d907a..f0af312 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -91,6 +91,8 @@
#define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_AF_IUCV 0xFBFB /* IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is less than this value
+ * then the frame is Ethernet II. Else it is 802.3 */
/*
* Non DIX types. Won't clash for 1500 types.
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 85c5073..ae513bd 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -174,6 +174,7 @@
struct proc_dir_entry *parent);
extern struct file *proc_ns_fget(int fd);
+extern void *PDE_DATA(const struct inode *);
#else
@@ -229,6 +230,8 @@
return ERR_PTR(-EINVAL);
}
+static inline void *PDE_DATA(const struct inode *inode) {BUG(); return NULL;}
+
#endif /* CONFIG_PROC_FS */
#if !defined(CONFIG_PROC_KCORE)
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index e156ce1..1849844 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -142,6 +142,16 @@
int seq_put_decimal_ll(struct seq_file *m, char delimiter,
long long num);
+static inline struct user_namespace *seq_user_ns(struct seq_file *seq)
+{
+#ifdef CONFIG_USER_NS
+ return seq->user_ns;
+#else
+ extern struct user_namespace init_user_ns;
+ return &init_user_ns;
+#endif
+}
+
#define SEQ_START_TOKEN ((void *)1)
/*
* Helpers for iteration over list_head-s in seq_files
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 6a0259d..62040f4 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -496,8 +496,16 @@
extern void tty_write_unlock(struct tty_struct *tty);
extern int tty_write_lock(struct tty_struct *tty, int ndelay);
#define tty_is_writelocked(tty) (mutex_is_locked(&tty->atomic_write_lock))
-
extern void tty_port_init(struct tty_port *port);
+extern void tty_port_link_device(struct tty_port *port,
+ struct tty_driver *driver, unsigned index);
+extern struct device *tty_port_register_device(struct tty_port *port,
+ struct tty_driver *driver, unsigned index,
+ struct device *device);
+extern struct device *tty_port_register_device_attr(struct tty_port *port,
+ struct tty_driver *driver, unsigned index,
+ struct device *device, void *drvdata,
+ const struct attribute_group **attr_grp);
extern int tty_port_alloc_xmit_buf(struct tty_port *port);
extern void tty_port_free_xmit_buf(struct tty_port *port);
extern void tty_port_put(struct tty_port *port);
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 6e6dbb7..04419c1 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -313,6 +313,7 @@
* Pointer to the tty data structures
*/
struct tty_struct **ttys;
+ struct tty_port **ports;
struct ktermios **termios;
void *driver_state;
diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h
new file mode 100644
index 0000000..8e522cbc
--- /dev/null
+++ b/include/linux/uidgid.h
@@ -0,0 +1,200 @@
+#ifndef _LINUX_UIDGID_H
+#define _LINUX_UIDGID_H
+
+/*
+ * A set of types for the internal kernel types representing uids and gids.
+ *
+ * The types defined in this header allow distinguishing which uids and gids in
+ * the kernel are values used by userspace and which uid and gid values are
+ * the internal kernel values. With the addition of user namespaces the values
+ * can be different. Using the type system makes it possible for the compiler
+ * to detect when we overlook these differences.
+ *
+ */
+#include <linux/types.h>
+#include <linux/highuid.h>
+
+struct user_namespace;
+extern struct user_namespace init_user_ns;
+
+#ifdef CONFIG_UIDGID_STRICT_TYPE_CHECKS
+
+typedef struct {
+ uid_t val;
+} kuid_t;
+
+
+typedef struct {
+ gid_t val;
+} kgid_t;
+
+#define KUIDT_INIT(value) (kuid_t){ value }
+#define KGIDT_INIT(value) (kgid_t){ value }
+
+static inline uid_t __kuid_val(kuid_t uid)
+{
+ return uid.val;
+}
+
+static inline gid_t __kgid_val(kgid_t gid)
+{
+ return gid.val;
+}
+
+#else
+
+typedef uid_t kuid_t;
+typedef gid_t kgid_t;
+
+static inline uid_t __kuid_val(kuid_t uid)
+{
+ return uid;
+}
+
+static inline gid_t __kgid_val(kgid_t gid)
+{
+ return gid;
+}
+
+#define KUIDT_INIT(value) ((kuid_t) value )
+#define KGIDT_INIT(value) ((kgid_t) value )
+
+#endif
+
+#define GLOBAL_ROOT_UID KUIDT_INIT(0)
+#define GLOBAL_ROOT_GID KGIDT_INIT(0)
+
+#define INVALID_UID KUIDT_INIT(-1)
+#define INVALID_GID KGIDT_INIT(-1)
+
+static inline bool uid_eq(kuid_t left, kuid_t right)
+{
+ return __kuid_val(left) == __kuid_val(right);
+}
+
+static inline bool gid_eq(kgid_t left, kgid_t right)
+{
+ return __kgid_val(left) == __kgid_val(right);
+}
+
+static inline bool uid_gt(kuid_t left, kuid_t right)
+{
+ return __kuid_val(left) > __kuid_val(right);
+}
+
+static inline bool gid_gt(kgid_t left, kgid_t right)
+{
+ return __kgid_val(left) > __kgid_val(right);
+}
+
+static inline bool uid_gte(kuid_t left, kuid_t right)
+{
+ return __kuid_val(left) >= __kuid_val(right);
+}
+
+static inline bool gid_gte(kgid_t left, kgid_t right)
+{
+ return __kgid_val(left) >= __kgid_val(right);
+}
+
+static inline bool uid_lt(kuid_t left, kuid_t right)
+{
+ return __kuid_val(left) < __kuid_val(right);
+}
+
+static inline bool gid_lt(kgid_t left, kgid_t right)
+{
+ return __kgid_val(left) < __kgid_val(right);
+}
+
+static inline bool uid_lte(kuid_t left, kuid_t right)
+{
+ return __kuid_val(left) <= __kuid_val(right);
+}
+
+static inline bool gid_lte(kgid_t left, kgid_t right)
+{
+ return __kgid_val(left) <= __kgid_val(right);
+}
+
+static inline bool uid_valid(kuid_t uid)
+{
+ return !uid_eq(uid, INVALID_UID);
+}
+
+static inline bool gid_valid(kgid_t gid)
+{
+ return !gid_eq(gid, INVALID_GID);
+}
+
+#ifdef CONFIG_USER_NS
+
+extern kuid_t make_kuid(struct user_namespace *from, uid_t uid);
+extern kgid_t make_kgid(struct user_namespace *from, gid_t gid);
+
+extern uid_t from_kuid(struct user_namespace *to, kuid_t uid);
+extern gid_t from_kgid(struct user_namespace *to, kgid_t gid);
+extern uid_t from_kuid_munged(struct user_namespace *to, kuid_t uid);
+extern gid_t from_kgid_munged(struct user_namespace *to, kgid_t gid);
+
+static inline bool kuid_has_mapping(struct user_namespace *ns, kuid_t uid)
+{
+ return from_kuid(ns, uid) != (uid_t) -1;
+}
+
+static inline bool kgid_has_mapping(struct user_namespace *ns, kgid_t gid)
+{
+ return from_kgid(ns, gid) != (gid_t) -1;
+}
+
+#else
+
+static inline kuid_t make_kuid(struct user_namespace *from, uid_t uid)
+{
+ return KUIDT_INIT(uid);
+}
+
+static inline kgid_t make_kgid(struct user_namespace *from, gid_t gid)
+{
+ return KGIDT_INIT(gid);
+}
+
+static inline uid_t from_kuid(struct user_namespace *to, kuid_t kuid)
+{
+ return __kuid_val(kuid);
+}
+
+static inline gid_t from_kgid(struct user_namespace *to, kgid_t kgid)
+{
+ return __kgid_val(kgid);
+}
+
+static inline uid_t from_kuid_munged(struct user_namespace *to, kuid_t kuid)
+{
+ uid_t uid = from_kuid(to, kuid);
+ if (uid == (uid_t)-1)
+ uid = overflowuid;
+ return uid;
+}
+
+static inline gid_t from_kgid_munged(struct user_namespace *to, kgid_t kgid)
+{
+ gid_t gid = from_kgid(to, kgid);
+ if (gid == (gid_t)-1)
+ gid = overflowgid;
+ return gid;
+}
+
+static inline bool kuid_has_mapping(struct user_namespace *ns, kuid_t uid)
+{
+ return true;
+}
+
+static inline bool kgid_has_mapping(struct user_namespace *ns, kgid_t gid)
+{
+ return true;
+}
+
+#endif /* CONFIG_USER_NS */
+
+#endif /* _LINUX_UIDGID_H */
diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
new file mode 100644
index 0000000..487b54c
--- /dev/null
+++ b/include/net/bluetooth/a2mp.h
@@ -0,0 +1,150 @@
+/*
+ Copyright (c) 2010,2011 Code Aurora Forum. All rights reserved.
+ Copyright (c) 2011,2012 Intel Corp.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 and
+ only version 2 as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+#ifndef __A2MP_H
+#define __A2MP_H
+
+#include <net/bluetooth/l2cap.h>
+
+#define A2MP_FEAT_EXT 0x8000
+
+enum amp_mgr_state {
+ READ_LOC_AMP_INFO,
+ READ_LOC_AMP_ASSOC,
+ READ_LOC_AMP_ASSOC_FINAL,
+ WRITE_REMOTE_AMP_ASSOC,
+};
+
+struct amp_mgr {
+ struct list_head list;
+ struct l2cap_conn *l2cap_conn;
+ struct l2cap_chan *a2mp_chan;
+ struct l2cap_chan *bredr_chan;
+ struct kref kref;
+ __u8 ident;
+ __u8 handle;
+ unsigned long state;
+ unsigned long flags;
+
+ struct list_head amp_ctrls;
+ struct mutex amp_ctrls_lock;
+};
+
+struct a2mp_cmd {
+ __u8 code;
+ __u8 ident;
+ __le16 len;
+ __u8 data[0];
+} __packed;
+
+/* A2MP command codes */
+#define A2MP_COMMAND_REJ 0x01
+struct a2mp_cmd_rej {
+ __le16 reason;
+ __u8 data[0];
+} __packed;
+
+#define A2MP_DISCOVER_REQ 0x02
+struct a2mp_discov_req {
+ __le16 mtu;
+ __le16 ext_feat;
+} __packed;
+
+struct a2mp_cl {
+ __u8 id;
+ __u8 type;
+ __u8 status;
+} __packed;
+
+#define A2MP_DISCOVER_RSP 0x03
+struct a2mp_discov_rsp {
+ __le16 mtu;
+ __le16 ext_feat;
+ struct a2mp_cl cl[0];
+} __packed;
+
+#define A2MP_CHANGE_NOTIFY 0x04
+#define A2MP_CHANGE_RSP 0x05
+
+#define A2MP_GETINFO_REQ 0x06
+struct a2mp_info_req {
+ __u8 id;
+} __packed;
+
+#define A2MP_GETINFO_RSP 0x07
+struct a2mp_info_rsp {
+ __u8 id;
+ __u8 status;
+ __le32 total_bw;
+ __le32 max_bw;
+ __le32 min_latency;
+ __le16 pal_cap;
+ __le16 assoc_size;
+} __packed;
+
+#define A2MP_GETAMPASSOC_REQ 0x08
+struct a2mp_amp_assoc_req {
+ __u8 id;
+} __packed;
+
+#define A2MP_GETAMPASSOC_RSP 0x09
+struct a2mp_amp_assoc_rsp {
+ __u8 id;
+ __u8 status;
+ __u8 amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_REQ 0x0A
+#define A2MP_DISCONNPHYSLINK_REQ 0x0C
+struct a2mp_physlink_req {
+ __u8 local_id;
+ __u8 remote_id;
+ __u8 amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_RSP 0x0B
+#define A2MP_DISCONNPHYSLINK_RSP 0x0D
+struct a2mp_physlink_rsp {
+ __u8 local_id;
+ __u8 remote_id;
+ __u8 status;
+} __packed;
+
+/* A2MP response status */
+#define A2MP_STATUS_SUCCESS 0x00
+#define A2MP_STATUS_INVALID_CTRL_ID 0x01
+#define A2MP_STATUS_UNABLE_START_LINK_CREATION 0x02
+#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS 0x02
+#define A2MP_STATUS_COLLISION_OCCURED 0x03
+#define A2MP_STATUS_DISCONN_REQ_RECVD 0x04
+#define A2MP_STATUS_PHYS_LINK_EXISTS 0x05
+#define A2MP_STATUS_SECURITY_VIOLATION 0x06
+
+extern struct list_head amp_mgr_list;
+extern struct mutex amp_mgr_list_lock;
+
+struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr);
+int amp_mgr_put(struct amp_mgr *mgr);
+u8 __next_ident(struct amp_mgr *mgr);
+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+ struct sk_buff *skb);
+struct amp_mgr *amp_mgr_lookup_by_state(u8 state);
+void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data);
+void a2mp_discover_amp(struct l2cap_chan *chan);
+void a2mp_send_getinfo_rsp(struct hci_dev *hdev);
+void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status);
+void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status);
+void a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status);
+
+#endif /* __A2MP_H */
diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
index 15d1817..7ea3db7 100644
--- a/include/net/bluetooth/amp.h
+++ b/include/net/bluetooth/amp.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2010-2012 The Linux Foundation. All rights reserved.
+ Copyright (c) 2011,2012 Intel Corp.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 and
@@ -14,280 +14,41 @@
#ifndef __AMP_H
#define __AMP_H
-/* AMP defaults */
-
-#define A2MP_RSP_TIMEOUT (8000) /* 8 seconds */
-
-/* A2MP Protocol */
-
-/* A2MP command codes */
-#define A2MP_COMMAND_REJ 0x01
-#define A2MP_DISCOVER_REQ 0x02
-#define A2MP_DISCOVER_RSP 0x03
-#define A2MP_CHANGE_NOTIFY 0x04
-#define A2MP_CHANGE_RSP 0x05
-#define A2MP_GETINFO_REQ 0x06
-#define A2MP_GETINFO_RSP 0x07
-#define A2MP_GETAMPASSOC_REQ 0x08
-#define A2MP_GETAMPASSOC_RSP 0x09
-#define A2MP_CREATEPHYSLINK_REQ 0x0A
-#define A2MP_CREATEPHYSLINK_RSP 0x0B
-#define A2MP_DISCONNPHYSLINK_REQ 0x0C
-#define A2MP_DISCONNPHYSLINK_RSP 0x0D
-
-struct a2mp_cmd_hdr {
- __u8 code;
- __u8 ident;
- __le16 len;
-} __packed;
-
-struct a2mp_cmd_rej {
- __le16 reason;
-} __packed;
-
-struct a2mp_discover_req {
- __le16 mtu;
- __le16 ext_feat;
-} __packed;
-
-struct a2mp_cl {
- __u8 id;
- __u8 type;
- __u8 status;
-} __packed;
-
-struct a2mp_discover_rsp {
- __le16 mtu;
- __le16 ext_feat;
- struct a2mp_cl cl[0];
-} __packed;
-
-struct a2mp_getinfo_req {
- __u8 id;
-} __packed;
-
-struct a2mp_getinfo_rsp {
- __u8 id;
- __u8 status;
- __le32 total_bw;
- __le32 max_bw;
- __le32 min_latency;
- __le16 pal_cap;
- __le16 assoc_size;
-} __packed;
-
-struct a2mp_getampassoc_req {
- __u8 id;
-} __packed;
-
-struct a2mp_getampassoc_rsp {
- __u8 id;
- __u8 status;
- __u8 amp_assoc[0];
-} __packed;
-
-struct a2mp_createphyslink_req {
- __u8 local_id;
- __u8 remote_id;
- __u8 amp_assoc[0];
-} __packed;
-
-struct a2mp_createphyslink_rsp {
- __u8 local_id;
- __u8 remote_id;
- __u8 status;
-} __packed;
-
-struct a2mp_disconnphyslink_req {
- __u8 local_id;
- __u8 remote_id;
-} __packed;
-
-struct a2mp_disconnphyslink_rsp {
- __u8 local_id;
- __u8 remote_id;
- __u8 status;
-} __packed;
-
-
-/* L2CAP-AMP module interface */
-int amp_init(void);
-void amp_exit(void);
-
-/* L2CAP-AMP fixed channel interface */
-void amp_conn_ind(struct hci_conn *hcon, struct sk_buff *skb);
-
-/* L2CAP-AMP link interface */
-void amp_create_physical(struct l2cap_conn *conn, struct sock *sk);
-void amp_accept_physical(struct l2cap_conn *conn, u8 id, struct sock *sk);
-
-/* AMP manager internals */
struct amp_ctrl {
- struct amp_mgr *mgr;
- __u8 id;
- __u8 type;
- __u8 status;
- __u32 total_bw;
- __u32 max_bw;
- __u32 min_latency;
- __u16 pal_cap;
- __u16 max_assoc_size;
+ struct list_head list;
+ struct kref kref;
+ __u8 id;
+ __u16 assoc_len_so_far;
+ __u16 assoc_rem_len;
+ __u16 assoc_len;
+ __u8 *assoc;
};
-struct amp_mgr {
- struct list_head list;
- __u8 discovered;
- __u8 next_ident;
- struct l2cap_conn *l2cap_conn;
- struct socket *a2mp_sock;
- struct list_head ctx_list;
- rwlock_t ctx_list_lock;
- struct amp_ctrl *ctrls; /* @@ TODO s.b. list of controllers */
- struct sk_buff *skb;
- __u8 connected;
-};
+int amp_ctrl_put(struct amp_ctrl *ctrl);
+void amp_ctrl_get(struct amp_ctrl *ctrl);
+struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id);
+struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id);
+void amp_ctrl_list_flush(struct amp_mgr *mgr);
-/* AMP Manager signalling contexts */
-#define AMP_GETAMPASSOC 1
-#define AMP_CREATEPHYSLINK 2
-#define AMP_ACCEPTPHYSLINK 3
-#define AMP_CREATELOGLINK 4
-#define AMP_ACCEPTLOGLINK 5
+struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
+ u8 remote_id, bool out);
-/* Get AMP Assoc sequence */
-#define AMP_GAA_INIT 0
-#define AMP_GAA_RLAA_COMPLETE 1
-struct amp_gaa_state {
- __u8 req_ident;
- __u16 len_so_far;
- __u8 *assoc;
-};
+int phylink_gen_key(struct hci_conn *hcon, u8 *data, u8 *len, u8 *type);
-/* Create Physical Link sequence */
-#define AMP_CPL_INIT 0
-#define AMP_CPL_DISC_RSP 1
-#define AMP_CPL_GETINFO_RSP 2
-#define AMP_CPL_GAA_RSP 3
-#define AMP_CPL_CPL_STATUS 4
-#define AMP_CPL_WRA_COMPLETE 5
-#define AMP_CPL_CHANNEL_SELECT 6
-#define AMP_CPL_RLA_COMPLETE 7
-#define AMP_CPL_PL_COMPLETE 8
-#define AMP_CPL_PL_CANCEL 9
-struct amp_cpl_state {
- __u8 remote_id;
- __u16 max_len;
- __u8 *remote_assoc;
- __u8 *local_assoc;
- __u16 len_so_far;
- __u16 rem_len;
- __u8 phy_handle;
-};
-
-/* Accept Physical Link sequence */
-#define AMP_APL_INIT 0
-#define AMP_APL_APL_STATUS 1
-#define AMP_APL_WRA_COMPLETE 2
-#define AMP_APL_PL_COMPLETE 3
-struct amp_apl_state {
- __u8 remote_id;
- __u8 req_ident;
- __u8 *remote_assoc;
- __u16 len_so_far;
- __u16 rem_len;
- __u8 phy_handle;
-};
-
-/* Create/Accept Logical Link sequence */
-#define AMP_LOG_INIT 0
-#define AMP_LOG_LL_STATUS 1
-#define AMP_LOG_LL_COMPLETE 2
-struct amp_log_state {
- __u8 remote_id;
-};
-
-/* Possible event types a context may wait for */
-#define AMP_INIT 0x01
-#define AMP_HCI_EVENT 0x02
-#define AMP_HCI_CMD_CMPLT 0x04
-#define AMP_HCI_CMD_STATUS 0x08
-#define AMP_A2MP_RSP 0x10
-#define AMP_KILLED 0x20
-#define AMP_CANCEL 0x40
-struct amp_ctx {
- struct list_head list;
- struct amp_mgr *mgr;
- struct hci_dev *hdev;
- __u8 type;
- __u8 state;
- union {
- struct amp_gaa_state gaa;
- struct amp_cpl_state cpl;
- struct amp_apl_state apl;
- } d;
- __u8 evt_type;
- __u8 evt_code;
- __u16 opcode;
- __u8 id;
- __u8 rsp_ident;
-
- struct sock *sk;
- struct amp_ctx *deferred;
- struct timer_list timer;
-};
-
-/* AMP work */
-struct amp_work_pl_timeout {
- struct work_struct work;
- struct amp_ctrl *ctrl;
-};
-struct amp_work_ctx_timeout {
- struct work_struct work;
- struct amp_ctx *ctx;
-};
-struct amp_work_data_ready {
- struct work_struct work;
- struct sock *sk;
- int bytes;
-};
-struct amp_work_state_change {
- struct work_struct work;
- struct sock *sk;
-};
-struct amp_work_conn_ind {
- struct work_struct work;
- struct hci_conn *hcon;
- struct sk_buff *skb;
-};
-struct amp_work_create_physical {
- struct work_struct work;
- struct l2cap_conn *conn;
- u8 id;
- struct sock *sk;
-};
-struct amp_work_accept_physical {
- struct work_struct work;
- struct l2cap_conn *conn;
- u8 id;
- struct sock *sk;
-};
-struct amp_work_cmd_cmplt {
- struct work_struct work;
- struct hci_dev *hdev;
- u16 opcode;
- struct sk_buff *skb;
-};
-struct amp_work_cmd_status {
- struct work_struct work;
- struct hci_dev *hdev;
- u16 opcode;
- u8 status;
-};
-struct amp_work_event {
- struct work_struct work;
- struct hci_dev *hdev;
- u8 event;
- struct sk_buff *skb;
-};
+void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr);
+void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle);
+void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr);
+void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
+ struct hci_conn *hcon);
+void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
+ struct hci_conn *hcon);
+void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
+ struct hci_conn *hcon);
+void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);
+void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle);
+void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon);
+void amp_create_logical_link(struct l2cap_chan *chan);
+void amp_disconnect_logical_link(struct hci_chan *hchan);
+void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason);
#endif /* __AMP_H */
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index e909195..10eb9b3 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2013 The Linux Foundation. All rights reserved.
+ Copyright (C) 2000-2001 Qualcomm Incorporated
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -25,20 +25,22 @@
#ifndef __BLUETOOTH_H
#define __BLUETOOTH_H
-#include <linux/types.h>
-#include <asm/byteorder.h>
-#include <linux/list.h>
#include <linux/poll.h>
#include <net/sock.h>
+#include <linux/seq_file.h>
#ifndef AF_BLUETOOTH
#define AF_BLUETOOTH 31
#define PF_BLUETOOTH AF_BLUETOOTH
#endif
+/* Bluetooth versions */
+#define BLUETOOTH_VER_1_1 1
+#define BLUETOOTH_VER_1_2 2
+#define BLUETOOTH_VER_2_0 3
+
/* Reserv for core and drivers use */
#define BT_SKB_RESERVE 8
-#define BT_SKB_RESERVE_80211 32
#define BTPROTO_L2CAP 0
#define BTPROTO_HCI 1
@@ -63,68 +65,56 @@
#define BT_SECURITY_LOW 1
#define BT_SECURITY_MEDIUM 2
#define BT_SECURITY_HIGH 3
-#define BT_SECURITY_VERY_HIGH 4
#define BT_DEFER_SETUP 7
+
#define BT_FLUSHABLE 8
+#define BT_FLUSHABLE_OFF 0
+#define BT_FLUSHABLE_ON 1
+
#define BT_POWER 9
struct bt_power {
__u8 force_active;
};
+#define BT_POWER_FORCE_ACTIVE_OFF 0
+#define BT_POWER_FORCE_ACTIVE_ON 1
-#define BT_AMP_POLICY 10
+#define BT_CHANNEL_POLICY 10
-/* Require BR/EDR (default policy)
- * AMP controllers cannot be used
- * Channel move requests from the remote device are denied
- * If the L2CAP channel is currently using AMP, move the channel to BR/EDR
+/* BR/EDR only (default policy)
+ * AMP controllers cannot be used.
+ * Channel move requests from the remote device are denied.
+ * If the L2CAP channel is currently using AMP, move the channel to BR/EDR.
*/
-#define BT_AMP_POLICY_REQUIRE_BR_EDR 0
+#define BT_CHANNEL_POLICY_BREDR_ONLY 0
-/* Prefer BR/EDR
- * Allow use of AMP controllers
- * If the L2CAP channel is currently on AMP, move it to BR/EDR
- * Channel move requests from the remote device are allowed
+/* BR/EDR Preferred
+ * Allow use of AMP controllers.
+ * If the L2CAP channel is currently on AMP, move it to BR/EDR.
+ * Channel move requests from the remote device are allowed.
*/
-#define BT_AMP_POLICY_PREFER_BR_EDR 1
+#define BT_CHANNEL_POLICY_BREDR_PREFERRED 1
-/* Prefer AMP
+/* AMP Preferred
* Allow use of AMP controllers
* If the L2CAP channel is currently on BR/EDR and AMP controller
- * resources are available, initiate a channel move to AMP
- * Channel move requests from the remote device are allowed
+ * resources are available, initiate a channel move to AMP.
+ * Channel move requests from the remote device are allowed.
* If the L2CAP socket has not been connected yet, try to create
* and configure the channel directly on an AMP controller rather
- * than BR/EDR
+ * than BR/EDR.
*/
-#define BT_AMP_POLICY_PREFER_AMP 2
+#define BT_CHANNEL_POLICY_AMP_PREFERRED 2
-#define BT_LE_PARAMS 100
+__printf(1, 2)
+int bt_info(const char *fmt, ...);
+__printf(1, 2)
+int bt_err(const char *fmt, ...);
-#define BT_LE_SCAN_WINDOW_MIN 0x0004
-#define BT_LE_SCAN_WINDOW_MAX 0x4000
-#define BT_LE_SCAN_WINDOW_DEF 0x0004
-
-#define BT_LE_SCAN_INTERVAL_MIN 0x0004
-#define BT_LE_SCAN_INTERVAL_MAX 0x4000
-#define BT_LE_SCAN_INTERVAL_DEF 0x0008
-
-#define BT_LE_CONN_INTERVAL_MIN 0x0006
-#define BT_LE_CONN_INTERVAL_MAX 0x0C80
-#define BT_LE_CONN_INTERVAL_MIN_DEF 0x0008
-#define BT_LE_CONN_INTERVAL_MAX_DEF 0x0100
-
-#define BT_LE_LATENCY_MAX 0x01F4
-#define BT_LE_LATENCY_DEF 0x0000
-
-#define BT_LE_SUP_TO_MIN 0x000A
-#define BT_LE_SUP_TO_MAX 0x0C80
-#define BT_LE_SUP_TO_DEFAULT 0X03E8
-
-#define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
-#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
-#define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg)
+#define BT_INFO(fmt, ...) bt_info(fmt "\n", ##__VA_ARGS__)
+#define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__)
+#define BT_DBG(fmt, ...) pr_debug(fmt "\n", ##__VA_ARGS__)
/* Connection and socket states */
enum {
@@ -139,63 +129,109 @@
BT_CLOSED
};
+/* If unused will be removed by compiler */
+static inline const char *state_to_string(int state)
+{
+ switch (state) {
+ case BT_CONNECTED:
+ return "BT_CONNECTED";
+ case BT_OPEN:
+ return "BT_OPEN";
+ case BT_BOUND:
+ return "BT_BOUND";
+ case BT_LISTEN:
+ return "BT_LISTEN";
+ case BT_CONNECT:
+ return "BT_CONNECT";
+ case BT_CONNECT2:
+ return "BT_CONNECT2";
+ case BT_CONFIG:
+ return "BT_CONFIG";
+ case BT_DISCONN:
+ return "BT_DISCONN";
+ case BT_CLOSED:
+ return "BT_CLOSED";
+ }
+
+ return "invalid state";
+}
+
/* BD Address */
typedef struct {
__u8 b[6];
} __packed bdaddr_t;
+/* BD Address type */
+#define BDADDR_BREDR 0x00
+#define BDADDR_LE_PUBLIC 0x01
+#define BDADDR_LE_RANDOM 0x02
+
+static inline bool bdaddr_type_is_valid(__u8 type)
+{
+ switch (type) {
+ case BDADDR_BREDR:
+ case BDADDR_LE_PUBLIC:
+ case BDADDR_LE_RANDOM:
+ return true;
+ }
+
+ return false;
+}
+
+static inline bool bdaddr_type_is_le(__u8 type)
+{
+ switch (type) {
+ case BDADDR_LE_PUBLIC:
+ case BDADDR_LE_RANDOM:
+ return true;
+ }
+
+ return false;
+}
+
#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0} })
#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff} })
/* Copy, swap, convert BD Address */
-static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2)
+static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2)
{
return memcmp(ba1, ba2, sizeof(bdaddr_t));
}
-static inline void bacpy(bdaddr_t *dst, bdaddr_t *src)
+static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)
{
memcpy(dst, src, sizeof(bdaddr_t));
}
void baswap(bdaddr_t *dst, bdaddr_t *src);
-char *batostr(bdaddr_t *ba);
-bdaddr_t *strtoba(char *str);
/* Common socket structures and functions */
#define bt_sk(__sk) ((struct bt_sock *) __sk)
-struct bt_le_params {
- __u8 prohibit_remote_chg;
- __u8 filter_policy;
- __u16 scan_interval;
- __u16 scan_window;
- __u16 interval_min;
- __u16 interval_max;
- __u16 latency;
- __u16 supervision_timeout;
- __u16 min_ce_len;
- __u16 max_ce_len;
- __u16 conn_timeout;
-};
-
struct bt_sock {
struct sock sk;
bdaddr_t src;
bdaddr_t dst;
struct list_head accept_q;
struct sock *parent;
- u32 defer_setup;
- struct bt_le_params le_params;
+ unsigned long flags;
+};
+
+enum {
+ BT_SK_DEFER_SETUP,
+ BT_SK_SUSPEND,
};
struct bt_sock_list {
struct hlist_head head;
rwlock_t lock;
+#ifdef CONFIG_PROC_FS
+ int (* custom_seq_show)(struct seq_file *, void *);
+#endif
};
int bt_sock_register(int proto, const struct net_proto_family *ops);
-int bt_sock_unregister(int proto);
+void bt_sock_unregister(int proto);
void bt_sock_link(struct bt_sock_list *l, struct sock *s);
void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
@@ -211,25 +247,35 @@
struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
/* Skb helpers */
-struct bt_l2cap_control {
- __u8 frame_type;
- __u8 final;
- __u8 sar;
- __u8 super;
- __u16 reqseq;
- __u16 txseq;
- __u8 poll;
- __u8 fcs;
+struct l2cap_ctrl {
+ unsigned int sframe:1,
+ poll:1,
+ final:1,
+ fcs:1,
+ sar:2,
+ super:2;
+ __u16 reqseq;
+ __u16 txseq;
+ __u8 retries;
+};
+
+struct hci_dev;
+
+typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status);
+
+struct hci_req_ctrl {
+ bool start;
+ u8 event;
+ hci_req_complete_t complete;
};
struct bt_skb_cb {
__u8 pkt_type;
__u8 incoming;
__u16 expect;
- __u8 retries;
__u8 force_active;
- unsigned short channel;
- struct bt_l2cap_control control;
+ struct l2cap_ctrl control;
+ struct hci_req_ctrl req;
};
#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
@@ -250,13 +296,11 @@
{
struct sk_buff *skb;
- release_sock(sk);
skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err);
if (skb) {
skb_reserve(skb, BT_SKB_RESERVE);
bt_cb(skb)->incoming = 0;
}
- lock_sock(sk);
if (!skb && *err)
return NULL;
@@ -277,7 +321,7 @@
return NULL;
}
-int bt_err(__u16 code);
+int bt_to_errno(__u16 code);
extern int hci_sock_init(void);
extern void hci_sock_cleanup(void);
@@ -285,6 +329,11 @@
extern int bt_sysfs_init(void);
extern void bt_sysfs_cleanup(void);
+extern int bt_procfs_init(struct net *net, const char *name,
+ struct bt_sock_list* sk_list,
+ int (* seq_show)(struct seq_file *, void *));
+extern void bt_procfs_cleanup(struct net *net, const char *name);
+
extern struct dentry *bt_debugfs;
int l2cap_init(void);
@@ -293,4 +342,6 @@
int sco_init(void);
void sco_exit(void);
+void bt_sock_reclassify_lock(struct sock *sk, int proto);
+
#endif /* __BLUETOOTH_H */
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index d88448f..db43501 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved.
+ Copyright (C) 2000-2001 Qualcomm Incorporated
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -25,11 +25,16 @@
#ifndef __HCI_H
#define __HCI_H
-#define HCI_MAX_ACL_SIZE 1500
+#define HCI_MAX_ACL_SIZE 1024
#define HCI_MAX_SCO_SIZE 255
#define HCI_MAX_EVENT_SIZE 260
#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4)
+#define HCI_LINK_KEY_SIZE 16
+#define HCI_AMP_LINK_KEY_SIZE (2 * HCI_LINK_KEY_SIZE)
+
+#define HCI_MAX_AMP_ASSOC_SIZE 672
+
/* HCI dev events */
#define HCI_DEV_REG 1
#define HCI_DEV_UNREG 2
@@ -37,7 +42,6 @@
#define HCI_DEV_DOWN 4
#define HCI_DEV_SUSPEND 5
#define HCI_DEV_RESUME 6
-#define HCI_DEV_WRITE 7
/* HCI notify events */
#define HCI_NOTIFY_CONN_ADD 1
@@ -52,15 +56,26 @@
#define HCI_RS232 4
#define HCI_PCI 5
#define HCI_SDIO 6
-#define HCI_SMD 7
/* HCI controller types */
#define HCI_BREDR 0x00
#define HCI_AMP 0x01
+/* First BR/EDR Controller shall have ID = 0 */
+#define HCI_BREDR_ID 0
+
+/* AMP controller status */
+#define AMP_CTRL_POWERED_DOWN 0x00
+#define AMP_CTRL_BLUETOOTH_ONLY 0x01
+#define AMP_CTRL_NO_CAPACITY 0x02
+#define AMP_CTRL_LOW_CAPACITY 0x03
+#define AMP_CTRL_MEDIUM_CAPACITY 0x04
+#define AMP_CTRL_HIGH_CAPACITY 0x05
+#define AMP_CTRL_FULL_CAPACITY 0x06
+
/* HCI device quirks */
enum {
- HCI_QUIRK_NO_RESET,
+ HCI_QUIRK_RESET_ON_CLOSE,
HCI_QUIRK_RAW_DEVICE,
HCI_QUIRK_FIXUP_BUFFER_SIZE
};
@@ -79,17 +94,42 @@
HCI_RAW,
+ HCI_RESET,
+};
+
+/*
+ * BR/EDR and/or LE controller flags: the flags defined here should represent
+ * states from the controller.
+ */
+enum {
HCI_SETUP,
HCI_AUTO_OFF,
+ HCI_RFKILLED,
HCI_MGMT,
HCI_PAIRABLE,
HCI_SERVICE_CACHE,
HCI_LINK_KEYS,
HCI_DEBUG_KEYS,
+ HCI_UNREGISTER,
- HCI_RESET,
+ HCI_LE_SCAN,
+ HCI_SSP_ENABLED,
+ HCI_HS_ENABLED,
+ HCI_LE_ENABLED,
+ HCI_LE_PERIPHERAL,
+ HCI_CONNECTABLE,
+ HCI_DISCOVERABLE,
+ HCI_LINK_SECURITY,
+ HCI_PERIODIC_INQ,
+ HCI_FAST_CONNECTABLE,
};
+/* A mask for the flags that are supposed to remain when a reset happens
+ * or the HCI device is closed.
+ */
+#define HCI_PERSISTENT_MASK (BIT(HCI_LE_SCAN) | BIT(HCI_PERIODIC_INQ) | \
+ BIT(HCI_FAST_CONNECTABLE))
+
/* HCI ioctl defines */
#define HCIDEVUP _IOW('H', 201, int)
#define HCIDEVDOWN _IOW('H', 202, int)
@@ -101,7 +141,6 @@
#define HCIGETCONNLIST _IOR('H', 212, int)
#define HCIGETCONNINFO _IOR('H', 213, int)
#define HCIGETAUTHINFO _IOR('H', 215, int)
-#define HCISETAUTHINFO _IOR('H', 216, int)
#define HCISETRAW _IOW('H', 220, int)
#define HCISETSCAN _IOW('H', 221, int)
@@ -119,13 +158,12 @@
#define HCIINQUIRY _IOR('H', 240, int)
/* HCI timeouts */
-#define HCI_DISCONN_AUTH_FAILED_TIMEOUT (10) /* 10 ms */
-#define HCI_CONNECT_TIMEOUT (40000) /* 40 seconds */
-#define HCI_DISCONN_TIMEOUT (2000) /* 2 seconds */
-#define HCI_PAIRING_TIMEOUT (60000) /* 60 seconds */
-#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */
-#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */
-#define HCI_CMD_TIMEOUT (5000) /* 5 seconds */
+#define HCI_DISCONN_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
+#define HCI_PAIRING_TIMEOUT msecs_to_jiffies(60000) /* 60 seconds */
+#define HCI_INIT_TIMEOUT msecs_to_jiffies(10000) /* 10 seconds */
+#define HCI_CMD_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
+#define HCI_ACL_TX_TIMEOUT msecs_to_jiffies(45000) /* 45 seconds */
+#define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
/* HCI data types */
#define HCI_COMMAND_PKT 0x01
@@ -161,25 +199,11 @@
#define ESCO_2EV5 0x0100
#define ESCO_3EV5 0x0200
-#define ESCO_WBS (ESCO_EV3 | (EDR_ESCO_MASK ^ ESCO_2EV3))
-
#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3)
#define EDR_ESCO_MASK (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5)
#define ALL_ESCO_MASK (SCO_ESCO_MASK | ESCO_EV3 | ESCO_EV4 | ESCO_EV5 | \
EDR_ESCO_MASK)
-/* Air Coding Format */
-#define ACF_CVSD 0x0000;
-#define ACF_ULAW 0x0001;
-#define ACF_ALAW 0x0002;
-#define ACF_TRANS 0x0003;
-
-/* Retransmission Effort */
-#define RE_NO_RETRANS 0x00;
-#define RE_POWER_CONSUMP 0x01;
-#define RE_LINK_QUALITY 0x02;
-#define RE_DONT_CARE 0xFF;
-
/* ACL flags */
#define ACL_START_NO_FLUSH 0x00
#define ACL_CONT 0x01
@@ -188,14 +212,13 @@
#define ACL_ACTIVE_BCAST 0x04
#define ACL_PICO_BCAST 0x08
-#define ACL_PB_MASK (ACL_CONT | ACL_START)
-
/* Baseband links */
#define SCO_LINK 0x00
#define ACL_LINK 0x01
#define ESCO_LINK 0x02
/* Low Energy links do not have defined link type. Use invented one */
#define LE_LINK 0x80
+#define AMP_LINK 0x81
/* LMP features */
#define LMP_3SLOT 0x01
@@ -225,6 +248,7 @@
#define LMP_EV4 0x01
#define LMP_EV5 0x02
+#define LMP_NO_BREDR 0x20
#define LMP_LE 0x40
#define LMP_SNIFF_SUBR 0x02
@@ -234,11 +258,18 @@
#define LMP_EDR_3S_ESCO 0x80
#define LMP_EXT_INQ 0x01
+#define LMP_SIMUL_LE_BR 0x02
#define LMP_SIMPLE_PAIR 0x08
#define LMP_NO_FLUSH 0x40
#define LMP_LSTO 0x01
#define LMP_INQ_TX_PWR 0x02
+#define LMP_EXTFEATURES 0x80
+
+/* Extended LMP features */
+#define LMP_HOST_SSP 0x01
+#define LMP_HOST_LE 0x02
+#define LMP_HOST_LE_BREDR 0x04
/* Connection modes */
#define HCI_CM_ACTIVE 0x0000
@@ -269,9 +300,59 @@
#define HCI_AT_GENERAL_BONDING 0x04
#define HCI_AT_GENERAL_BONDING_MITM 0x05
+/* Link Key types */
+#define HCI_LK_COMBINATION 0x00
+#define HCI_LK_LOCAL_UNIT 0x01
+#define HCI_LK_REMOTE_UNIT 0x02
+#define HCI_LK_DEBUG_COMBINATION 0x03
+#define HCI_LK_UNAUTH_COMBINATION 0x04
+#define HCI_LK_AUTH_COMBINATION 0x05
+#define HCI_LK_CHANGED_COMBINATION 0x06
+/* The spec doesn't define types for SMP keys, the _MASTER suffix is implied */
+#define HCI_SMP_STK 0x80
+#define HCI_SMP_STK_SLAVE 0x81
+#define HCI_SMP_LTK 0x82
+#define HCI_SMP_LTK_SLAVE 0x83
+
+/* ---- HCI Error Codes ---- */
+#define HCI_ERROR_AUTH_FAILURE 0x05
+#define HCI_ERROR_CONNECTION_TIMEOUT 0x08
+#define HCI_ERROR_REJ_BAD_ADDR 0x0f
+#define HCI_ERROR_REMOTE_USER_TERM 0x13
+#define HCI_ERROR_REMOTE_LOW_RESOURCES 0x14
+#define HCI_ERROR_REMOTE_POWER_OFF 0x15
+#define HCI_ERROR_LOCAL_HOST_TERM 0x16
+#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18
+
/* Flow control modes */
-#define HCI_PACKET_BASED_FLOW_CTL_MODE 0x00
-#define HCI_BLOCK_BASED_FLOW_CTL_MODE 0x01
+#define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00
+#define HCI_FLOW_CTL_MODE_BLOCK_BASED 0x01
+
+/* The core spec defines 127 as the "not available" value */
+#define HCI_TX_POWER_INVALID 127
+
+/* Extended Inquiry Response field types */
+#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_CLASS_OF_DEV 0x0D /* Class of Device */
+#define EIR_SSP_HASH_C 0x0E /* Simple Pairing Hash C */
+#define EIR_SSP_RAND_R 0x0F /* Simple Pairing Randomizer R */
+#define EIR_DEVICE_ID 0x10 /* device ID */
+
+/* Low Energy Advertising Flags */
+#define LE_AD_LIMITED 0x01 /* Limited Discoverable */
+#define LE_AD_GENERAL 0x02 /* General Discoverable */
+#define LE_AD_NO_BREDR 0x04 /* BR/EDR not supported */
+#define LE_AD_SIM_LE_BREDR_CTRL 0x08 /* Simultaneous LE & BR/EDR Controller */
+#define LE_AD_SIM_LE_BREDR_HOST 0x10 /* Simultaneous LE & BR/EDR Host */
/* ----- HCI Commands ---- */
#define HCI_OP_NOP 0x0000
@@ -285,6 +366,8 @@
#define HCI_OP_INQUIRY_CANCEL 0x0402
+#define HCI_OP_PERIODIC_INQ 0x0403
+
#define HCI_OP_EXIT_PERIODIC_INQ 0x0404
#define HCI_OP_CREATE_CONN 0x0405
@@ -329,12 +412,7 @@
#define HCI_OP_LINK_KEY_REPLY 0x040b
struct hci_cp_link_key_reply {
bdaddr_t bdaddr;
- __u8 link_key[16];
-} __packed;
-
-struct hci_rp_link_key_reply {
- __u8 status;
- bdaddr_t bdaddr;
+ __u8 link_key[HCI_LINK_KEY_SIZE];
} __packed;
#define HCI_OP_LINK_KEY_NEG_REPLY 0x040c
@@ -413,11 +491,6 @@
__le16 handle;
} __packed;
-#define HCI_OP_READ_CLOCK_OFFSET 0x041f
-struct hci_cp_read_clock_offset {
- __le16 handle;
-} __packed;
-
#define HCI_OP_SETUP_SYNC_CONN 0x0428
struct hci_cp_setup_sync_conn {
__le16 handle;
@@ -465,6 +538,14 @@
#define HCI_OP_USER_CONFIRM_NEG_REPLY 0x042d
+#define HCI_OP_USER_PASSKEY_REPLY 0x042e
+struct hci_cp_user_passkey_reply {
+ bdaddr_t bdaddr;
+ __le32 passkey;
+} __packed;
+
+#define HCI_OP_USER_PASSKEY_NEG_REPLY 0x042f
+
#define HCI_OP_REMOTE_OOB_DATA_REPLY 0x0430
struct hci_cp_remote_oob_data_reply {
bdaddr_t bdaddr;
@@ -483,43 +564,43 @@
__u8 reason;
} __packed;
-#define HCI_OP_CREATE_PHYS_LINK 0x0435
-struct hci_cp_create_phys_link {
+#define HCI_OP_CREATE_PHY_LINK 0x0435
+struct hci_cp_create_phy_link {
__u8 phy_handle;
__u8 key_len;
- __u8 type;
- __u8 data[32];
+ __u8 key_type;
+ __u8 key[HCI_AMP_LINK_KEY_SIZE];
} __packed;
-#define HCI_OP_ACCEPT_PHYS_LINK 0x0436
-struct hci_cp_accept_phys_link {
+#define HCI_OP_ACCEPT_PHY_LINK 0x0436
+struct hci_cp_accept_phy_link {
__u8 phy_handle;
__u8 key_len;
- __u8 type;
- __u8 data[32];
+ __u8 key_type;
+ __u8 key[HCI_AMP_LINK_KEY_SIZE];
} __packed;
-#define HCI_OP_DISCONN_PHYS_LINK 0x0437
-struct hci_cp_disconn_phys_link {
+#define HCI_OP_DISCONN_PHY_LINK 0x0437
+struct hci_cp_disconn_phy_link {
__u8 phy_handle;
__u8 reason;
} __packed;
-struct hci_ext_fs {
+struct ext_flow_spec {
__u8 id;
- __u8 type;
- __le16 max_sdu;
- __le32 sdu_arr_time;
- __le32 acc_latency;
+ __u8 stype;
+ __le16 msdu;
+ __le32 sdu_itime;
+ __le32 acc_lat;
__le32 flush_to;
} __packed;
#define HCI_OP_CREATE_LOGICAL_LINK 0x0438
#define HCI_OP_ACCEPT_LOGICAL_LINK 0x0439
-struct hci_cp_create_logical_link {
- __u8 phy_handle;
- struct hci_ext_fs tx_fs;
- struct hci_ext_fs rx_fs;
+struct hci_cp_create_accept_logical_link {
+ __u8 phy_handle;
+ struct ext_flow_spec tx_flow_spec;
+ struct ext_flow_spec rx_flow_spec;
} __packed;
#define HCI_OP_DISCONN_LOGICAL_LINK 0x043a
@@ -539,13 +620,6 @@
__u8 flow_spec_id;
} __packed;
-#define HCI_OP_FLOW_SPEC_MODIFY 0x043c
-struct hci_cp_flow_spec_modify {
- __le16 log_handle;
- struct hci_ext_fs tx_fs;
- struct hci_ext_fs rx_fs;
-} __packed;
-
#define HCI_OP_SNIFF_MODE 0x0803
struct hci_cp_sniff_mode {
__le16 handle;
@@ -706,12 +780,6 @@
__le16 voice_setting;
} __packed;
-#define HCI_OP_WRITE_AUTOMATIC_FLUSH_TIMEOUT 0x0c28
-struct hci_cp_write_automatic_flush_timeout {
- __le16 handle;
- __le16 timeout;
-} __packed;
-
#define HCI_OP_HOST_BUFFER_SIZE 0x0c33
struct hci_cp_host_buffer_size {
__le16 acl_mtu;
@@ -720,20 +788,14 @@
__le16 sco_max_pkt;
} __packed;
-#define HCI_OP_WRITE_CURRENT_IAC_LAP 0x0c3a
-struct hci_cp_write_current_iac_lap {
- __u8 num_current_iac;
- __u8 lap[6];
-} __packed;
-
#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];
+ __u8 fec;
+ __u8 data[HCI_MAX_EIR_LENGTH];
} __packed;
#define HCI_OP_READ_SSP_MODE 0x0c55
@@ -755,38 +817,9 @@
} __packed;
#define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58
-
-#define HCI_OP_READ_LL_TIMEOUT 0x0c61
-struct hci_rp_read_ll_timeout {
+struct hci_rp_read_inq_rsp_tx_power {
__u8 status;
- __le16 timeout;
-} __packed;
-
-#define HCI_OP_WRITE_LL_TIMEOUT 0x0c62
-struct hci_cp_write_ll_timeout {
- __le16 timeout;
-} __packed;
-
-#define HCI_OP_SET_EVENT_MASK_PAGE2 0x0c63
-struct hci_cp_set_event_mask_page2 {
- __u8 mask[8];
-} __packed;
-
-#define HCI_OP_READ_LOCATION_DATA 0x0c64
-struct hci_rp_read_location_data {
- __u8 status;
- __u8 loc_dom_aware;
- __u8 loc_dom;
- __u8 loc_dom_opts;
- __u8 loc_opts;
-} __packed;
-
-#define HCI_OP_WRITE_LOCATION_DATA 0x0c65
-struct hci_cp_write_location_data {
- __u8 loc_dom_aware;
- __u8 loc_dom;
- __u8 loc_dom_opts;
- __u8 loc_opts;
+ __s8 tx_power;
} __packed;
#define HCI_OP_READ_FLOW_CONTROL_MODE 0x0c66
@@ -795,31 +828,10 @@
__u8 mode;
} __packed;
-#define HCI_OP_WRITE_FLOW_CONTROL_MODE 0x0c67
-struct hci_cp_write_flow_control_mode {
- __u8 mode;
-} __packed;
-
-#define HCI_OP_READ_BE_FLUSH_TIMEOUT 0x0c69
-struct hci_cp_read_be_flush_timeout {
- __le16 log_handle;
-} __packed;
-
-struct hci_rp_read_be_flush_timeout {
- __u8 status;
- __le32 timeout;
-} __packed;
-
-#define HCI_OP_WRITE_BE_FLUSH_TIMEOUT 0x0c6a
-struct hci_cp_write_be_flush_timeout {
- __le16 log_handle;
- __le32 timeout;
-} __packed;
-
-#define HCI_OP_SHORT_RANGE_MODE 0x0c6b
-struct hci_cp_short_range_mode {
- __u8 phy_handle;
- __u8 mode;
+#define HCI_OP_WRITE_LE_HOST_SUPPORTED 0x0c6d
+struct hci_cp_write_le_host_supported {
+ __u8 le;
+ __u8 simul;
} __packed;
#define HCI_OP_READ_LOCAL_VERSION 0x1001
@@ -845,6 +857,9 @@
} __packed;
#define HCI_OP_READ_LOCAL_EXT_FEATURES 0x1004
+struct hci_cp_read_local_ext_features {
+ __u8 page;
+} __packed;
struct hci_rp_read_local_ext_features {
__u8 status;
__u8 page;
@@ -871,21 +886,33 @@
struct hci_rp_read_data_block_size {
__u8 status;
__le16 max_acl_len;
- __le16 data_block_len;
+ __le16 block_len;
__le16 num_blocks;
} __packed;
-#define HCI_OP_READ_RSSI 0x1405
-struct hci_cp_read_rssi {
- __le16 handle;
+#define HCI_OP_READ_PAGE_SCAN_ACTIVITY 0x0c1b
+struct hci_rp_read_page_scan_activity {
+ __u8 status;
+ __le16 interval;
+ __le16 window;
} __packed;
-struct hci_rp_read_rssi {
- __u8 status;
- __le16 handle;
- __s8 rssi;
+#define HCI_OP_WRITE_PAGE_SCAN_ACTIVITY 0x0c1c
+struct hci_cp_write_page_scan_activity {
+ __le16 interval;
+ __le16 window;
} __packed;
+#define HCI_OP_READ_PAGE_SCAN_TYPE 0x0c46
+struct hci_rp_read_page_scan_type {
+ __u8 status;
+ __u8 type;
+} __packed;
+
+#define HCI_OP_WRITE_PAGE_SCAN_TYPE 0x0c47
+ #define PAGE_SCAN_TYPE_STANDARD 0x00
+ #define PAGE_SCAN_TYPE_INTERLACED 0x01
+
#define HCI_OP_READ_LOCAL_AMP_INFO 0x1409
struct hci_rp_read_local_amp_info {
__u8 status;
@@ -907,12 +934,11 @@
__le16 len_so_far;
__le16 max_len;
} __packed;
-
struct hci_rp_read_local_amp_assoc {
__u8 status;
__u8 phy_handle;
__le16 rem_len;
- __u8 frag[248];
+ __u8 frag[0];
} __packed;
#define HCI_OP_WRITE_REMOTE_AMP_ASSOC 0x140b
@@ -920,9 +946,8 @@
__u8 phy_handle;
__le16 len_so_far;
__le16 rem_len;
- __u8 frag[248];
+ __u8 frag[0];
} __packed;
-
struct hci_rp_write_remote_amp_assoc {
__u8 status;
__u8 phy_handle;
@@ -940,19 +965,49 @@
__u8 le_max_pkt;
} __packed;
-#define HCI_OP_LE_SET_SCAN_PARAMETERS 0x200b
-struct hci_cp_le_set_scan_parameters {
- __u8 type;
- __le16 interval;
- __le16 window;
- __u8 own_bdaddr_type;
- __u8 filter;
+#define HCI_OP_LE_READ_LOCAL_FEATURES 0x2003
+struct hci_rp_le_read_local_features {
+ __u8 status;
+ __u8 features[8];
} __packed;
+#define HCI_OP_LE_READ_ADV_TX_POWER 0x2007
+struct hci_rp_le_read_adv_tx_power {
+ __u8 status;
+ __s8 tx_power;
+} __packed;
+
+#define HCI_MAX_AD_LENGTH 31
+
+#define HCI_OP_LE_SET_ADV_DATA 0x2008
+struct hci_cp_le_set_adv_data {
+ __u8 length;
+ __u8 data[HCI_MAX_AD_LENGTH];
+} __packed;
+
+#define HCI_OP_LE_SET_ADV_ENABLE 0x200a
+
+#define LE_SCAN_PASSIVE 0x00
+#define LE_SCAN_ACTIVE 0x01
+
+#define HCI_OP_LE_SET_SCAN_PARAM 0x200b
+struct hci_cp_le_set_scan_param {
+ __u8 type;
+ __le16 interval;
+ __le16 window;
+ __u8 own_address_type;
+ __u8 filter_policy;
+} __packed;
+
+#define LE_SCAN_DISABLE 0x00
+#define LE_SCAN_ENABLE 0x01
+#define LE_SCAN_FILTER_DUP_DISABLE 0x00
+#define LE_SCAN_FILTER_DUP_ENABLE 0x01
+
#define HCI_OP_LE_SET_SCAN_ENABLE 0x200c
struct hci_cp_le_set_scan_enable {
- __u8 enable;
- __u8 filter_dup;
+ __u8 enable;
+ __u8 filter_dup;
} __packed;
#define HCI_OP_LE_CREATE_CONN 0x200d
@@ -973,24 +1028,10 @@
#define HCI_OP_LE_CREATE_CONN_CANCEL 0x200e
-#define HCI_OP_LE_READ_WHITE_LIST_SIZE 0x200F
+#define HCI_OP_LE_READ_WHITE_LIST_SIZE 0x200f
struct hci_rp_le_read_white_list_size {
- __u8 status;
- __u8 size;
-} __packed;
-
-#define HCI_OP_LE_CLEAR_WHITE_LIST 0x2010
-
-#define HCI_OP_LE_ADD_DEV_WHITE_LIST 0x2011
-struct hci_cp_le_add_dev_white_list {
- __u8 addr_type;
- bdaddr_t addr;
-} __packed;
-
-#define HCI_OP_LE_REMOVE_DEV_WHITE_LIST 0x2012
-struct hci_cp_le_remove_dev_white_list {
- __u8 addr_type;
- bdaddr_t addr;
+ __u8 status;
+ __u8 size;
} __packed;
#define HCI_OP_LE_CONN_UPDATE 0x2013
@@ -1004,16 +1045,6 @@
__le16 max_ce_len;
} __packed;
-#define HCI_OP_LE_ENCRYPT 0x2017
-struct hci_cp_le_encrypt {
- __u8 key[16];
- __u8 data[16];
-} __packed;
-struct hci_cp_le_encrypt_reply {
- __u8 status;
- __u8 encrypted[16];
-} __packed;
-
#define HCI_OP_LE_START_ENC 0x2019
struct hci_cp_le_start_enc {
__le16 handle;
@@ -1041,6 +1072,12 @@
__le16 handle;
} __packed;
+#define HCI_OP_LE_READ_SUPPORTED_STATES 0x201c
+struct hci_rp_le_read_supported_states {
+ __u8 status;
+ __u8 le_states[8];
+} __packed;
+
/* ---- HCI Events ---- */
#define HCI_EV_INQUIRY_COMPLETE 0x01
@@ -1154,9 +1191,14 @@
} __packed;
#define HCI_EV_NUM_COMP_PKTS 0x13
+struct hci_comp_pkts_info {
+ __le16 handle;
+ __le16 count;
+} __packed;
+
struct hci_ev_num_comp_pkts {
__u8 num_hndl;
- /* variable length part */
+ struct hci_comp_pkts_info handles[0];
} __packed;
#define HCI_EV_MODE_CHANGE 0x14
@@ -1180,7 +1222,7 @@
#define HCI_EV_LINK_KEY_NOTIFY 0x18
struct hci_ev_link_key_notify {
bdaddr_t bdaddr;
- __u8 link_key[16];
+ __u8 link_key[HCI_LINK_KEY_SIZE];
__u8 key_type;
} __packed;
@@ -1276,6 +1318,12 @@
__u8 data[240];
} __packed;
+#define HCI_EV_KEY_REFRESH_COMPLETE 0x30
+struct hci_ev_key_refresh_complete {
+ __u8 status;
+ __le16 handle;
+} __packed;
+
#define HCI_EV_IO_CAPA_REQUEST 0x31
struct hci_ev_io_capa_request {
bdaddr_t bdaddr;
@@ -1296,8 +1344,8 @@
} __packed;
#define HCI_EV_USER_PASSKEY_REQUEST 0x34
-struct hci_ev_user_passkey_request {
- bdaddr_t bdaddr;
+struct hci_ev_user_passkey_req {
+ bdaddr_t bdaddr;
} __packed;
#define HCI_EV_REMOTE_OOB_DATA_REQUEST 0x35
@@ -1311,12 +1359,24 @@
bdaddr_t bdaddr;
} __packed;
-#define HCI_EV_USER_PASSKEY_NOTIFICATION 0x3b
-struct hci_ev_user_passkey_notification {
+#define HCI_EV_USER_PASSKEY_NOTIFY 0x3b
+struct hci_ev_user_passkey_notify {
bdaddr_t bdaddr;
__le32 passkey;
} __packed;
+#define HCI_KEYPRESS_STARTED 0
+#define HCI_KEYPRESS_ENTERED 1
+#define HCI_KEYPRESS_ERASED 2
+#define HCI_KEYPRESS_CLEARED 3
+#define HCI_KEYPRESS_COMPLETED 4
+
+#define HCI_EV_KEYPRESS_NOTIFY 0x3c
+struct hci_ev_keypress_notify {
+ bdaddr_t bdaddr;
+ __u8 type;
+} __packed;
+
#define HCI_EV_REMOTE_HOST_FEATURES 0x3d
struct hci_ev_remote_host_features {
bdaddr_t bdaddr;
@@ -1328,7 +1388,55 @@
__u8 subevent;
} __packed;
+#define HCI_EV_PHY_LINK_COMPLETE 0x40
+struct hci_ev_phy_link_complete {
+ __u8 status;
+ __u8 phy_handle;
+} __packed;
+
+#define HCI_EV_CHANNEL_SELECTED 0x41
+struct hci_ev_channel_selected {
+ __u8 phy_handle;
+} __packed;
+
+#define HCI_EV_DISCONN_PHY_LINK_COMPLETE 0x42
+struct hci_ev_disconn_phy_link_complete {
+ __u8 status;
+ __u8 phy_handle;
+ __u8 reason;
+} __packed;
+
+#define HCI_EV_LOGICAL_LINK_COMPLETE 0x45
+struct hci_ev_logical_link_complete {
+ __u8 status;
+ __le16 handle;
+ __u8 phy_handle;
+ __u8 flow_spec_id;
+} __packed;
+
+#define HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE 0x46
+struct hci_ev_disconn_logical_link_complete {
+ __u8 status;
+ __le16 handle;
+ __u8 reason;
+} __packed;
+
+#define HCI_EV_NUM_COMP_BLOCKS 0x48
+struct hci_comp_blocks_info {
+ __le16 handle;
+ __le16 pkts;
+ __le16 blocks;
+} __packed;
+
+struct hci_ev_num_comp_blocks {
+ __le16 num_blocks;
+ __u8 num_hndl;
+ struct hci_comp_blocks_info handles[0];
+} __packed;
+
/* Low energy meta events */
+#define LE_CONN_ROLE_MASTER 0x00
+
#define HCI_EV_LE_CONN_COMPLETE 0x01
struct hci_ev_le_conn_complete {
__u8 status;
@@ -1342,6 +1450,14 @@
__u8 clk_accurancy;
} __packed;
+#define HCI_EV_LE_LTK_REQ 0x05
+struct hci_ev_le_ltk_req {
+ __le16 handle;
+ __u8 random[8];
+ __le16 ediv;
+} __packed;
+
+/* Advertising report event types */
#define ADV_IND 0x00
#define ADV_DIRECT_IND 0x01
#define ADV_SCAN_IND 0x02
@@ -1360,81 +1476,6 @@
__u8 data[0];
} __packed;
-#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03
-struct hci_ev_le_conn_update_complete {
- __u8 status;
- __le16 handle;
- __le16 interval;
- __le16 latency;
- __le16 supervision_timeout;
-} __packed;
-
-#define HCI_EV_LE_LTK_REQ 0x05
-struct hci_ev_le_ltk_req {
- __le16 handle;
- __u8 random[8];
- __le16 ediv;
-} __packed;
-
-#define HCI_EV_PHYS_LINK_COMPLETE 0x40
-struct hci_ev_phys_link_complete {
- __u8 status;
- __u8 phy_handle;
-} __packed;
-
-#define HCI_EV_CHANNEL_SELECTED 0x41
-struct hci_ev_channel_selected {
- __u8 phy_handle;
-} __packed;
-
-#define HCI_EV_DISCONN_PHYS_LINK_COMPLETE 0x42
-struct hci_ev_disconn_phys_link_complete {
- __u8 status;
- __u8 phy_handle;
- __u8 reason;
-} __packed;
-
-#define HCI_EV_LOG_LINK_COMPLETE 0x45
-struct hci_ev_log_link_complete {
- __u8 status;
- __le16 log_handle;
- __u8 phy_handle;
- __u8 flow_spec_id;
-} __packed;
-
-#define HCI_EV_DISCONN_LOG_LINK_COMPLETE 0x46
-struct hci_ev_disconn_log_link_complete {
- __u8 status;
- __le16 log_handle;
- __u8 reason;
-} __packed;
-
-#define HCI_EV_FLOW_SPEC_MODIFY_COMPLETE 0x47
-struct hci_ev_flow_spec_modify_complete {
- __u8 status;
- __le16 log_handle;
-} __packed;
-
-#define HCI_EV_NUM_COMP_BLOCKS 0x48
-struct hci_ev_num_comp_blocks {
- __le16 total_num_blocks;
- __u8 num_hndl;
- /* variable length part */
-} __packed;
-
-#define HCI_EV_SHORT_RANGE_MODE_COMPLETE 0x4c
-struct hci_ev_short_range_mode_complete {
- __u8 status;
- __u8 phy_handle;
- __u8 mode;
-} __packed;
-
-#define HCI_EV_AMP_STATUS_CHANGE 0x4d
-struct hci_ev_amp_status_change {
- __u8 status;
- __u8 amp_status;
-} __packed;
-
/* Internal events generated by Bluetooth stack */
#define HCI_EV_STACK_INTERNAL 0xfd
struct hci_ev_stack_internal {
@@ -1482,8 +1523,6 @@
__u8 dlen;
} __packed;
-#ifdef __KERNEL__
-#include <linux/skbuff.h>
static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb)
{
return (struct hci_event_hdr *) skb->data;
@@ -1498,15 +1537,14 @@
{
return (struct hci_sco_hdr *) skb->data;
}
-#endif
/* Command opcode pack/unpack */
-#define hci_opcode_pack(ogf, ocf) (__u16) ((ocf & 0x03ff)|(ogf << 10))
+#define hci_opcode_pack(ogf, ocf) ((__u16) ((ocf & 0x03ff)|(ogf << 10)))
#define hci_opcode_ogf(op) (op >> 10)
#define hci_opcode_ocf(op) (op & 0x03ff)
/* ACL handle and flags pack/unpack */
-#define hci_handle_pack(h, f) (__u16) ((h & 0x0fff)|(f << 12))
+#define hci_handle_pack(h, f) ((__u16) ((h & 0x0fff)|(f << 12)))
#define hci_handle(h) (h & 0x0fff)
#define hci_flags(h) (h >> 12)
@@ -1529,7 +1567,8 @@
#define HCI_DEV_NONE 0xffff
#define HCI_CHANNEL_RAW 0
-#define HCI_CHANNEL_CONTROL 1
+#define HCI_CHANNEL_MONITOR 2
+#define HCI_CHANNEL_CONTROL 3
struct hci_filter {
unsigned long type_mask;
@@ -1595,8 +1634,6 @@
__u32 mtu;
__u32 cnt;
__u32 pkts;
- __u8 pending_sec_level;
- __u8 ssp_mode;
};
struct hci_dev_req {
@@ -1635,4 +1672,6 @@
};
#define IREQ_CACHE_FLUSH 0x0001
+extern bool enable_hs;
+
#endif /* __HCI_H */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index f462d83..57123ee 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1,7 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, The Linux Foundation. All rights reserved.
- Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -27,10 +26,9 @@
#define __HCI_CORE_H
#include <net/bluetooth/hci.h>
-#include <linux/wakelock.h>
-/* HCI upper protocols */
-#define HCI_PROTO_L2CAP 0
-#define HCI_PROTO_SCO 1
+
+/* HCI priority */
+#define HCI_PRIO_MAX 7
/* HCI Core structures */
struct inquiry_data {
@@ -45,30 +43,41 @@
};
struct inquiry_entry {
- struct inquiry_entry *next;
+ struct list_head all; /* inq_cache.all */
+ struct list_head list; /* unknown or resolve */
+ enum {
+ NAME_NOT_KNOWN,
+ NAME_NEEDED,
+ NAME_PENDING,
+ NAME_KNOWN,
+ } name_state;
__u32 timestamp;
struct inquiry_data data;
};
-struct inquiry_cache {
- spinlock_t lock;
+struct discovery_state {
+ int type;
+ enum {
+ DISCOVERY_STOPPED,
+ DISCOVERY_STARTING,
+ DISCOVERY_FINDING,
+ DISCOVERY_RESOLVING,
+ DISCOVERY_STOPPING,
+ } state;
+ struct list_head all; /* All devices found during inquiry */
+ struct list_head unknown; /* Name state not known */
+ struct list_head resolve; /* Name needs to be resolved */
__u32 timestamp;
- struct inquiry_entry *list;
};
struct hci_conn_hash {
struct list_head list;
- spinlock_t lock;
unsigned int acl_num;
+ unsigned int amp_num;
unsigned int sco_num;
unsigned int le_num;
};
-struct hci_chan_list {
- struct list_head list;
- spinlock_t lock;
-};
-
struct bdaddr_list {
struct list_head list;
bdaddr_t bdaddr;
@@ -77,40 +86,28 @@
struct bt_uuid {
struct list_head list;
u8 uuid[16];
+ u8 size;
u8 svc_hint;
};
-struct key_master_id {
+struct smp_ltk {
+ struct list_head list;
+ bdaddr_t bdaddr;
+ u8 bdaddr_type;
+ u8 authenticated;
+ u8 type;
+ u8 enc_size;
__le16 ediv;
u8 rand[8];
-} __packed;
-
-#define KEY_TYPE_LE_BASE 0x11
-#define KEY_TYPE_LTK 0x11
-#define KEY_TYPE_IRK 0x12
-#define KEY_TYPE_CSRK 0x13
-
-struct link_key_data {
- bdaddr_t bdaddr;
- u8 addr_type;
- u8 key_type;
u8 val[16];
- u8 pin_len;
- u8 auth;
- u8 dlen;
- u8 data[0];
} __packed;
struct link_key {
struct list_head list;
bdaddr_t bdaddr;
- u8 addr_type;
- u8 key_type;
- u8 val[16];
+ u8 type;
+ u8 val[HCI_LINK_KEY_SIZE];
u8 pin_len;
- u8 auth;
- u8 dlen;
- u8 data[0];
};
struct oob_data {
@@ -120,18 +117,29 @@
u8 randomizer[16];
};
-struct adv_entry {
- struct list_head list;
- bdaddr_t bdaddr;
- u8 bdaddr_type;
- u8 flags;
+struct le_scan_params {
+ u8 type;
+ u16 interval;
+ u16 window;
+ int timeout;
};
+#define HCI_MAX_SHORT_NAME_LENGTH 10
+
+struct amp_assoc {
+ __u16 len;
+ __u16 offset;
+ __u16 rem_len;
+ __u16 len_so_far;
+ __u8 data[HCI_MAX_AMP_ASSOC_SIZE];
+};
+
+#define HCI_MAX_PAGES 3
+
#define NUM_REASSEMBLY 4
struct hci_dev {
struct list_head list;
- spinlock_t lock;
- atomic_t refcnt;
+ struct mutex lock;
char name[8];
unsigned long flags;
@@ -140,20 +148,33 @@
__u8 dev_type;
bdaddr_t bdaddr;
__u8 dev_name[HCI_MAX_NAME_LENGTH];
+ __u8 short_name[HCI_MAX_SHORT_NAME_LENGTH];
__u8 eir[HCI_MAX_EIR_LENGTH];
__u8 dev_class[3];
__u8 major_class;
__u8 minor_class;
- __u8 features[8];
+ __u8 max_page;
+ __u8 features[HCI_MAX_PAGES][8];
+ __u8 le_features[8];
+ __u8 le_white_list_size;
+ __u8 le_states[8];
__u8 commands[64];
- __u8 ssp_mode;
__u8 hci_ver;
__u16 hci_rev;
__u8 lmp_ver;
__u16 manufacturer;
- __le16 lmp_subver;
+ __u16 lmp_subver;
__u16 voice_setting;
__u8 io_capability;
+ __s8 inq_tx_power;
+ __u16 page_scan_interval;
+ __u16 page_scan_window;
+ __u8 page_scan_type;
+
+ __u16 devid_source;
+ __u16 devid_vendor;
+ __u16 devid_product;
+ __u16 devid_version;
__u16 pkt_type;
__u16 esco_type;
@@ -175,7 +196,11 @@
__u32 amp_max_flush_to;
__u32 amp_be_flush_to;
- __s8 is_wbs;
+ struct amp_assoc loc_assoc;
+
+ __u8 flow_ctl_mode;
+
+ unsigned int auto_accept_delay;
unsigned long quirks;
@@ -184,37 +209,44 @@
unsigned int sco_cnt;
unsigned int le_cnt;
- __u8 flow_ctl_mode;
-
unsigned int acl_mtu;
unsigned int sco_mtu;
unsigned int le_mtu;
unsigned int acl_pkts;
unsigned int sco_pkts;
unsigned int le_pkts;
- unsigned int le_white_list_size;
- unsigned int data_block_len;
+ __u16 block_len;
+ __u16 block_mtu;
+ __u16 num_blocks;
+ __u16 block_cnt;
unsigned long acl_last_tx;
unsigned long sco_last_tx;
unsigned long le_last_tx;
struct workqueue_struct *workqueue;
+ struct workqueue_struct *req_workqueue;
struct work_struct power_on;
- struct work_struct power_off;
- struct timer_list off_timer;
+ struct delayed_work power_off;
+
+ __u16 discov_timeout;
+ struct delayed_work discov_off;
+
+ struct delayed_work service_cache;
struct timer_list cmd_timer;
- struct tasklet_struct cmd_task;
- struct tasklet_struct rx_task;
- struct tasklet_struct tx_task;
+
+ struct work_struct rx_work;
+ struct work_struct cmd_work;
+ struct work_struct tx_work;
struct sk_buff_head rx_q;
struct sk_buff_head raw_q;
struct sk_buff_head cmd_q;
+ struct sk_buff *recv_evt;
struct sk_buff *sent_cmd;
struct sk_buff *reassembly[NUM_REASSEMBLY];
@@ -223,143 +255,107 @@
__u32 req_status;
__u32 req_result;
- __u16 init_last_cmd;
+ struct list_head mgmt_pending;
- struct crypto_blkcipher *tfm;
-
- struct inquiry_cache inq_cache;
+ struct discovery_state discovery;
struct hci_conn_hash conn_hash;
- struct hci_chan_list chan_list;
struct list_head blacklist;
struct list_head uuids;
struct list_head link_keys;
+ struct list_head long_term_keys;
+
struct list_head remote_oob_data;
- struct list_head adv_entries;
- rwlock_t adv_entries_lock;
- struct timer_list adv_timer;
-
- struct timer_list disco_timer;
- struct timer_list disco_le_timer;
- __u8 disco_state;
- int disco_int_phase;
- int disco_int_count;
-
struct hci_dev_stats stat;
- struct sk_buff_head driver_init;
-
- void *driver_data;
- void *core_data;
-
atomic_t promisc;
struct dentry *debugfs;
- struct device *parent;
struct device dev;
struct rfkill *rfkill;
- struct module *owner;
+ unsigned long dev_flags;
+
+ struct delayed_work le_scan_disable;
+
+ struct work_struct le_scan;
+ struct le_scan_params le_scan_params;
+
+ __s8 adv_tx_power;
+ __u8 adv_data[HCI_MAX_AD_LENGTH];
+ __u8 adv_data_len;
int (*open)(struct hci_dev *hdev);
int (*close)(struct hci_dev *hdev);
int (*flush)(struct hci_dev *hdev);
+ int (*setup)(struct hci_dev *hdev);
int (*send)(struct sk_buff *skb);
- void (*destruct)(struct hci_dev *hdev);
void (*notify)(struct hci_dev *hdev, unsigned int evt);
int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
};
+#define HCI_PHY_HANDLE(handle) (handle & 0xff)
+
struct hci_conn {
struct list_head list;
atomic_t refcnt;
- spinlock_t lock;
bdaddr_t dst;
- __u8 dst_id;
- __u8 dst_type;
+ __u8 dst_type;
__u16 handle;
__u16 state;
__u8 mode;
__u8 type;
- __u8 out;
+ bool out;
__u8 attempt;
__u8 dev_class[3];
- __u8 features[8];
- __u8 ssp_mode;
+ __u8 features[HCI_MAX_PAGES][8];
__u16 interval;
__u16 pkt_type;
__u16 link_policy;
__u32 link_mode;
+ __u8 key_type;
__u8 auth_type;
__u8 sec_level;
__u8 pending_sec_level;
__u8 pin_length;
__u8 enc_key_size;
__u8 io_capability;
- __u8 auth_initiator;
- __u8 power_save;
+ __u32 passkey_notify;
+ __u8 passkey_entered;
__u16 disc_timeout;
- __u16 conn_timeout;
- unsigned long pend;
+ unsigned long flags;
__u8 remote_cap;
- __u8 remote_oob;
__u8 remote_auth;
-
- __s8 rssi_threshold;
- __u16 rssi_update_interval;
- __u8 rssi_update_thresh_exceed;
+ __u8 remote_id;
+ bool flush_key;
unsigned int sent;
struct sk_buff_head data_q;
+ struct list_head chan_list;
- struct timer_list disc_timer;
+ struct delayed_work disc_work;
struct timer_list idle_timer;
- struct delayed_work rssi_update_work;
- struct timer_list encrypt_pause_timer;
+ struct timer_list auto_accept_timer;
- struct work_struct work_add;
- struct work_struct work_del;
- struct wake_lock idle_lock;
struct device dev;
- atomic_t devref;
struct hci_dev *hdev;
void *l2cap_data;
void *sco_data;
- void *priv;
-
- __u8 link_key[16];
- __u8 key_type;
+ void *smp_conn;
+ struct amp_mgr *amp_mgr;
struct hci_conn *link;
- /* Low Energy SMP pairing data */
- __u8 oob; /* OOB pairing supported */
- __u8 tk_valid; /* TK value is valid */
- __u8 cfm_pending; /* CONFIRM cmd may be sent */
- __u8 preq[7]; /* Pairing Request */
- __u8 prsp[7]; /* Pairing Response */
- __u8 prnd[16]; /* Pairing Random */
- __u8 pcnf[16]; /* Pairing Confirm */
- __u8 tk[16]; /* Temporary Key */
- __u8 smp_key_size;
- __u8 sec_req;
- __u8 auth;
- void *smp_conn;
- struct timer_list smp_timer;
- __u8 conn_valid;
- __u8 hidp_session_valid;
-
-
void (*connect_cfm_cb) (struct hci_conn *conn, u8 status);
void (*security_cfm_cb) (struct hci_conn *conn, u8 status);
void (*disconn_cfm_cb) (struct hci_conn *conn, u8 reason);
@@ -367,47 +363,56 @@
struct hci_chan {
struct list_head list;
- struct hci_dev *hdev;
- __u16 state;
- atomic_t refcnt;
- __u16 ll_handle;
- struct hci_ext_fs tx_fs;
- struct hci_ext_fs rx_fs;
- struct hci_conn *conn;
- void *l2cap_sk;
+ __u16 handle;
+ struct hci_conn *conn;
+ struct sk_buff_head data_q;
+ unsigned int sent;
+ __u8 state;
};
-extern struct hci_proto *hci_proto[];
extern struct list_head hci_dev_list;
extern struct list_head hci_cb_list;
extern rwlock_t hci_dev_list_lock;
extern rwlock_t hci_cb_list_lock;
+/* ----- HCI interface to upper protocols ----- */
+extern int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
+extern void l2cap_connect_cfm(struct hci_conn *hcon, u8 status);
+extern int l2cap_disconn_ind(struct hci_conn *hcon);
+extern void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason);
+extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt);
+extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb,
+ u16 flags);
+
+extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags);
+extern void sco_connect_cfm(struct hci_conn *hcon, __u8 status);
+extern void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason);
+extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);
+
/* ----- Inquiry cache ----- */
#define INQUIRY_CACHE_AGE_MAX (HZ*30) /* 30 seconds */
-#define INQUIRY_ENTRY_AGE_MAX (HZ*60*60) /* 1 Hour */
+#define INQUIRY_ENTRY_AGE_MAX (HZ*60) /* 60 seconds */
-#define inquiry_cache_lock(c) spin_lock(&c->lock)
-#define inquiry_cache_unlock(c) spin_unlock(&c->lock)
-#define inquiry_cache_lock_bh(c) spin_lock_bh(&c->lock)
-#define inquiry_cache_unlock_bh(c) spin_unlock_bh(&c->lock)
-
-static inline void inquiry_cache_init(struct hci_dev *hdev)
+static inline void discovery_init(struct hci_dev *hdev)
{
- struct inquiry_cache *c = &hdev->inq_cache;
- spin_lock_init(&c->lock);
- c->list = NULL;
+ hdev->discovery.state = DISCOVERY_STOPPED;
+ INIT_LIST_HEAD(&hdev->discovery.all);
+ INIT_LIST_HEAD(&hdev->discovery.unknown);
+ INIT_LIST_HEAD(&hdev->discovery.resolve);
}
+bool hci_discovery_active(struct hci_dev *hdev);
+
+void hci_discovery_set_state(struct hci_dev *hdev, int state);
+
static inline int inquiry_cache_empty(struct hci_dev *hdev)
{
- struct inquiry_cache *c = &hdev->inq_cache;
- return c->list == NULL;
+ return list_empty(&hdev->discovery.all);
}
static inline long inquiry_cache_age(struct hci_dev *hdev)
{
- struct inquiry_cache *c = &hdev->inq_cache;
+ struct discovery_state *c = &hdev->discovery;
return jiffies - c->timestamp;
}
@@ -416,35 +421,51 @@
return jiffies - e->timestamp;
}
-struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
-void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data);
+struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev,
+ bdaddr_t *bdaddr);
+struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev,
+ bdaddr_t *bdaddr);
+struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev,
+ bdaddr_t *bdaddr,
+ int state);
+void hci_inquiry_cache_update_resolve(struct hci_dev *hdev,
+ struct inquiry_entry *ie);
+bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
+ bool name_known, bool *ssp);
/* ----- HCI Connections ----- */
enum {
HCI_CONN_AUTH_PEND,
+ HCI_CONN_REAUTH_PEND,
HCI_CONN_ENCRYPT_PEND,
HCI_CONN_RSWITCH_PEND,
HCI_CONN_MODE_CHANGE_PEND,
HCI_CONN_SCO_SETUP_PEND,
+ HCI_CONN_LE_SMP_PEND,
+ HCI_CONN_MGMT_CONNECTED,
+ HCI_CONN_SSP_ENABLED,
+ HCI_CONN_POWER_SAVE,
+ HCI_CONN_REMOTE_OOB,
};
-static inline void hci_conn_hash_init(struct hci_dev *hdev)
+static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
{
- struct hci_conn_hash *h = &hdev->conn_hash;
- INIT_LIST_HEAD(&h->list);
- spin_lock_init(&h->lock);
- h->acl_num = 0;
- h->sco_num = 0;
+ struct hci_dev *hdev = conn->hdev;
+ return test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
+ test_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
}
static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
{
struct hci_conn_hash *h = &hdev->conn_hash;
- list_add(&c->list, &h->list);
+ list_add_rcu(&c->list, &h->list);
switch (c->type) {
case ACL_LINK:
h->acl_num++;
break;
+ case AMP_LINK:
+ h->amp_num++;
+ break;
case LE_LINK:
h->le_num++;
break;
@@ -458,11 +479,17 @@
static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
{
struct hci_conn_hash *h = &hdev->conn_hash;
- list_del(&c->list);
+
+ list_del_rcu(&c->list);
+ synchronize_rcu();
+
switch (c->type) {
case ACL_LINK:
h->acl_num--;
break;
+ case AMP_LINK:
+ h->amp_num--;
+ break;
case LE_LINK:
h->le_num--;
break;
@@ -473,55 +500,60 @@
}
}
+static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
+{
+ struct hci_conn_hash *h = &hdev->conn_hash;
+ switch (type) {
+ case ACL_LINK:
+ return h->acl_num;
+ case AMP_LINK:
+ return h->amp_num;
+ case LE_LINK:
+ return h->le_num;
+ case SCO_LINK:
+ case ESCO_LINK:
+ return h->sco_num;
+ default:
+ return 0;
+ }
+}
+
static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
__u16 handle)
{
struct hci_conn_hash *h = &hdev->conn_hash;
- struct list_head *p;
struct hci_conn *c;
- list_for_each(p, &h->list) {
- c = list_entry(p, struct hci_conn, list);
- if (c->handle == handle)
- return c;
- }
- return NULL;
-}
+ rcu_read_lock();
-static inline void hci_chan_list_init(struct hci_dev *hdev)
-{
- struct hci_chan_list *h = &hdev->chan_list;
- INIT_LIST_HEAD(&h->list);
- spin_lock_init(&h->lock);
+ list_for_each_entry_rcu(c, &h->list, list) {
+ if (c->handle == handle) {
+ rcu_read_unlock();
+ return c;
+ }
+ }
+ rcu_read_unlock();
+
+ return NULL;
}
static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
__u8 type, bdaddr_t *ba)
{
struct hci_conn_hash *h = &hdev->conn_hash;
- struct list_head *p;
struct hci_conn *c;
- list_for_each(p, &h->list) {
- c = list_entry(p, struct hci_conn, list);
- if (c->type == type && !bacmp(&c->dst, ba))
- return c;
- }
- return NULL;
-}
+ rcu_read_lock();
-static inline struct hci_conn *hci_conn_hash_lookup_id(struct hci_dev *hdev,
- bdaddr_t *ba, __u8 id)
-{
- struct hci_conn_hash *h = &hdev->conn_hash;
- struct list_head *p;
- struct hci_conn *c;
-
- list_for_each(p, &h->list) {
- c = list_entry(p, struct hci_conn, list);
- if (!bacmp(&c->dst, ba) && (c->dst_id == id))
+ list_for_each_entry_rcu(c, &h->list, list) {
+ if (c->type == type && !bacmp(&c->dst, ba)) {
+ rcu_read_unlock();
return c;
+ }
}
+
+ rcu_read_unlock();
+
return NULL;
}
@@ -529,166 +561,176 @@
__u8 type, __u16 state)
{
struct hci_conn_hash *h = &hdev->conn_hash;
- struct list_head *p;
struct hci_conn *c;
- list_for_each(p, &h->list) {
- c = list_entry(p, struct hci_conn, list);
- if (c->type == type && c->state == state)
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(c, &h->list, list) {
+ if (c->type == type && c->state == state) {
+ rcu_read_unlock();
return c;
+ }
}
+
+ rcu_read_unlock();
+
return NULL;
}
-static inline struct hci_chan *hci_chan_list_lookup_handle(struct hci_dev *hdev,
- __u16 handle)
-{
- struct hci_chan_list *l = &hdev->chan_list;
- struct list_head *p;
- struct hci_chan *c;
-
- list_for_each(p, &l->list) {
- c = list_entry(p, struct hci_chan, list);
- if (c->ll_handle == handle)
- return c;
- }
- return NULL;
-}
-
-static inline struct hci_chan *hci_chan_list_lookup_id(struct hci_dev *hdev,
- __u8 handle)
-{
- struct hci_chan_list *l = &hdev->chan_list;
- struct list_head *p;
- struct hci_chan *c;
-
- list_for_each(p, &l->list) {
- c = list_entry(p, struct hci_chan, list);
- if (c->conn->handle == handle)
- return c;
- }
- return NULL;
-}
-
-void hci_acl_connect(struct hci_conn *conn);
-void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
-void hci_add_sco(struct hci_conn *conn, __u16 handle);
+void hci_disconnect(struct hci_conn *conn, __u8 reason);
void hci_setup_sync(struct hci_conn *conn, __u16 handle);
void hci_sco_setup(struct hci_conn *conn, __u8 status);
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type,
__u16 pkt_type, bdaddr_t *dst);
-struct hci_conn *hci_le_conn_add(struct hci_dev *hdev, bdaddr_t *dst,
- __u8 addr_type);
int hci_conn_del(struct hci_conn *conn);
-void hci_conn_hash_flush(struct hci_dev *hdev, u8 is_process);
+void hci_conn_hash_flush(struct hci_dev *hdev);
void hci_conn_check_pending(struct hci_dev *hdev);
-struct hci_chan *hci_chan_add(struct hci_dev *hdev);
-int hci_chan_del(struct hci_chan *chan);
-static inline void hci_chan_hold(struct hci_chan *chan)
-{
- atomic_inc(&chan->refcnt);
-}
-int hci_chan_put(struct hci_chan *chan);
-
-struct hci_chan *hci_chan_create(struct hci_chan *chan,
- struct hci_ext_fs *tx_fs,
- struct hci_ext_fs *rx_fs);
-void hci_chan_modify(struct hci_chan *chan,
- struct hci_ext_fs *tx_fs,
- struct hci_ext_fs *rx_fs);
+struct hci_chan *hci_chan_create(struct hci_conn *conn);
+void hci_chan_del(struct hci_chan *chan);
+void hci_chan_list_flush(struct hci_conn *conn);
+struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle);
struct hci_conn *hci_connect(struct hci_dev *hdev, int type,
- __u16 pkt_type, bdaddr_t *dst,
- __u8 sec_level, __u8 auth_type);
-struct hci_conn *hci_le_connect(struct hci_dev *hdev, __u16 pkt_type,
- bdaddr_t *dst, __u8 sec_level,
- __u8 auth_type,
- struct bt_le_params *le_params);
-void hci_le_add_dev_white_list(struct hci_dev *hdev, bdaddr_t *dst);
-void hci_le_remove_dev_white_list(struct hci_dev *hdev, bdaddr_t *dst);
-void hci_le_cancel_create_connect(struct hci_dev *hdev, bdaddr_t *dst);
+ __u16 pkt_type, bdaddr_t *dst,
+ __u8 dst_type, __u8 sec_level, __u8 auth_type);
int hci_conn_check_link_mode(struct hci_conn *conn);
+int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level);
int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type);
int hci_conn_change_link_key(struct hci_conn *conn);
int hci_conn_switch_role(struct hci_conn *conn, __u8 role);
-void hci_disconnect(struct hci_conn *conn, __u8 reason);
-void hci_disconnect_amp(struct hci_conn *conn, __u8 reason);
void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active);
-void hci_conn_enter_sniff_mode(struct hci_conn *conn);
-void hci_conn_hold_device(struct hci_conn *conn);
-void hci_conn_put_device(struct hci_conn *conn);
+/*
+ * hci_conn_get() and hci_conn_put() are used to control the life-time of an
+ * "hci_conn" object. They do not guarantee that the hci_conn object is running,
+ * working or anything else. They just guarantee that the object is available
+ * and can be dereferenced. So you can use its locks, local variables and any
+ * other constant data.
+ * Before accessing runtime data, you _must_ lock the object and then check that
+ * it is still running. As soon as you release the locks, the connection might
+ * get dropped, though.
+ *
+ * On the other hand, hci_conn_hold() and hci_conn_drop() are used to control
+ * how long the underlying connection is held. So every channel that runs on the
+ * hci_conn object calls this to prevent the connection from disappearing. As
+ * long as you hold a device, you must also guarantee that you have a valid
+ * reference to the device via hci_conn_get() (or the initial reference from
+ * hci_conn_add()).
+ * The hold()/drop() ref-count is known to drop below 0 sometimes, which doesn't
+ * break because nobody cares for that. But this means, we cannot use
+ * _get()/_drop() in it, but require the caller to have a valid ref (FIXME).
+ */
-void hci_conn_set_rssi_reporter(struct hci_conn *conn,
- s8 rssi_threshold, u16 interval, u8 updateOnThreshExceed);
-void hci_conn_unset_rssi_reporter(struct hci_conn *conn);
-
-static inline void hci_conn_hold(struct hci_conn *conn)
+static inline void hci_conn_get(struct hci_conn *conn)
{
- atomic_inc(&conn->refcnt);
- del_timer(&conn->disc_timer);
+ get_device(&conn->dev);
}
static inline void hci_conn_put(struct hci_conn *conn)
{
+ put_device(&conn->dev);
+}
+
+static inline void hci_conn_hold(struct hci_conn *conn)
+{
+ BT_DBG("hcon %p orig refcnt %d", conn, atomic_read(&conn->refcnt));
+
+ atomic_inc(&conn->refcnt);
+ cancel_delayed_work(&conn->disc_work);
+}
+
+static inline void hci_conn_drop(struct hci_conn *conn)
+{
+ BT_DBG("hcon %p orig refcnt %d", conn, atomic_read(&conn->refcnt));
+
if (atomic_dec_and_test(&conn->refcnt)) {
unsigned long timeo;
- if (conn->type == ACL_LINK || conn->type == LE_LINK) {
+
+ switch (conn->type) {
+ case ACL_LINK:
+ case LE_LINK:
del_timer(&conn->idle_timer);
if (conn->state == BT_CONNECTED) {
- timeo = msecs_to_jiffies(conn->disc_timeout);
+ timeo = conn->disc_timeout;
if (!conn->out)
- timeo *= 4;
- } else
+ timeo *= 20;
+ } else {
timeo = msecs_to_jiffies(10);
- } else
+ }
+ break;
+
+ case AMP_LINK:
+ timeo = conn->disc_timeout;
+ break;
+
+ default:
timeo = msecs_to_jiffies(10);
- mod_timer(&conn->disc_timer, jiffies + timeo);
+ break;
+ }
+
+ cancel_delayed_work(&conn->disc_work);
+ queue_delayed_work(conn->hdev->workqueue,
+ &conn->disc_work, timeo);
}
}
/* ----- HCI Devices ----- */
-static inline void __hci_dev_put(struct hci_dev *d)
-{
- if (atomic_dec_and_test(&d->refcnt))
- d->destruct(d);
-}
-
static inline void hci_dev_put(struct hci_dev *d)
{
- __hci_dev_put(d);
- module_put(d->owner);
-}
+ BT_DBG("%s orig refcnt %d", d->name,
+ atomic_read(&d->dev.kobj.kref.refcount));
-static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d)
-{
- atomic_inc(&d->refcnt);
- return d;
+ put_device(&d->dev);
}
static inline struct hci_dev *hci_dev_hold(struct hci_dev *d)
{
- if (try_module_get(d->owner))
- return __hci_dev_hold(d);
- return NULL;
+ BT_DBG("%s orig refcnt %d", d->name,
+ atomic_read(&d->dev.kobj.kref.refcount));
+
+ get_device(&d->dev);
+ return d;
}
-#define hci_dev_lock(d) spin_lock(&d->lock)
-#define hci_dev_unlock(d) spin_unlock(&d->lock)
-#define hci_dev_lock_bh(d) spin_lock_bh(&d->lock)
-#define hci_dev_unlock_bh(d) spin_unlock_bh(&d->lock)
+#define hci_dev_lock(d) mutex_lock(&d->lock)
+#define hci_dev_unlock(d) mutex_unlock(&d->lock)
+
+#define to_hci_dev(d) container_of(d, struct hci_dev, dev)
+#define to_hci_conn(c) container_of(c, struct hci_conn, dev)
+
+static inline void *hci_get_drvdata(struct hci_dev *hdev)
+{
+ return dev_get_drvdata(&hdev->dev);
+}
+
+static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
+{
+ dev_set_drvdata(&hdev->dev, data);
+}
+
+/* hci_dev_list shall be locked */
+static inline uint8_t __hci_num_ctrl(void)
+{
+ uint8_t count = 0;
+ struct list_head *p;
+
+ list_for_each(p, &hci_dev_list) {
+ count++;
+ }
+
+ return count;
+}
struct hci_dev *hci_dev_get(int index);
-struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
-struct hci_dev *hci_dev_get_type(__u8 amp_type);
+struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src);
struct hci_dev *hci_alloc_dev(void);
void hci_free_dev(struct hci_dev *hdev);
int hci_register_dev(struct hci_dev *hdev);
-int hci_unregister_dev(struct hci_dev *hdev);
+void hci_unregister_dev(struct hci_dev *hdev);
int hci_suspend_dev(struct hci_dev *hdev);
int hci_resume_dev(struct hci_dev *hdev);
int hci_dev_open(__u16 dev);
@@ -701,23 +743,28 @@
int hci_get_conn_list(void __user *arg);
int hci_get_conn_info(struct hci_dev *hdev, void __user *arg);
int hci_get_auth_info(struct hci_dev *hdev, void __user *arg);
-int hci_set_auth_info(struct hci_dev *hdev, void __user *arg);
int hci_inquiry(void __user *arg);
-struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
+struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
+ bdaddr_t *bdaddr);
int hci_blacklist_clear(struct hci_dev *hdev);
+int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
int hci_uuids_clear(struct hci_dev *hdev);
int hci_link_keys_clear(struct hci_dev *hdev);
struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
-int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
- u8 *key, u8 type, u8 pin_len);
-struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]);
-struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
- bdaddr_t *bdaddr, u8 type);
-int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, u8 type,
- u8 auth, u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]);
+int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
+ bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
+struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]);
+int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
+ int new_key, u8 authenticated, u8 tk[16], u8 enc_size,
+ __le16 ediv, u8 rand[8]);
+struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 addr_type);
+int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int hci_smp_ltks_clear(struct hci_dev *hdev);
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_remote_oob_data_clear(struct hci_dev *hdev);
@@ -727,86 +774,99 @@
u8 *randomizer);
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
-#define ADV_CLEAR_TIMEOUT (3*60*HZ) /* Three minutes */
-int hci_adv_entries_clear(struct hci_dev *hdev);
-struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr);
-int hci_add_adv_entry(struct hci_dev *hdev,
- struct hci_ev_le_advertising_info *ev);
-
-void hci_del_off_timer(struct hci_dev *hdev);
-
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
int hci_recv_frame(struct sk_buff *skb);
int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count);
int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count);
-int hci_register_sysfs(struct hci_dev *hdev);
-void hci_unregister_sysfs(struct hci_dev *hdev);
+void hci_init_sysfs(struct hci_dev *hdev);
+int hci_add_sysfs(struct hci_dev *hdev);
+void hci_del_sysfs(struct hci_dev *hdev);
void hci_conn_init_sysfs(struct hci_conn *conn);
void hci_conn_add_sysfs(struct hci_conn *conn);
void hci_conn_del_sysfs(struct hci_conn *conn);
-#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev))
+#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->dev.parent = (pdev))
/* ----- LMP capabilities ----- */
-#define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH)
-#define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT)
-#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF)
-#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
-#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO)
-#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR)
-#define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH)
-#define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE)
+#define lmp_encrypt_capable(dev) ((dev)->features[0][0] & LMP_ENCRYPT)
+#define lmp_rswitch_capable(dev) ((dev)->features[0][0] & LMP_RSWITCH)
+#define lmp_hold_capable(dev) ((dev)->features[0][0] & LMP_HOLD)
+#define lmp_sniff_capable(dev) ((dev)->features[0][0] & LMP_SNIFF)
+#define lmp_park_capable(dev) ((dev)->features[0][1] & LMP_PARK)
+#define lmp_inq_rssi_capable(dev) ((dev)->features[0][3] & LMP_RSSI_INQ)
+#define lmp_esco_capable(dev) ((dev)->features[0][3] & LMP_ESCO)
+#define lmp_bredr_capable(dev) (!((dev)->features[0][4] & LMP_NO_BREDR))
+#define lmp_le_capable(dev) ((dev)->features[0][4] & LMP_LE)
+#define lmp_sniffsubr_capable(dev) ((dev)->features[0][5] & LMP_SNIFF_SUBR)
+#define lmp_pause_enc_capable(dev) ((dev)->features[0][5] & LMP_PAUSE_ENC)
+#define lmp_ext_inq_capable(dev) ((dev)->features[0][6] & LMP_EXT_INQ)
+#define lmp_le_br_capable(dev) (!!((dev)->features[0][6] & LMP_SIMUL_LE_BR))
+#define lmp_ssp_capable(dev) ((dev)->features[0][6] & LMP_SIMPLE_PAIR)
+#define lmp_no_flush_capable(dev) ((dev)->features[0][6] & LMP_NO_FLUSH)
+#define lmp_lsto_capable(dev) ((dev)->features[0][7] & LMP_LSTO)
+#define lmp_inq_tx_pwr_capable(dev) ((dev)->features[0][7] & LMP_INQ_TX_PWR)
+#define lmp_ext_feat_capable(dev) ((dev)->features[0][7] & LMP_EXTFEATURES)
+
+/* ----- Extended LMP capabilities ----- */
+#define lmp_host_ssp_capable(dev) ((dev)->features[1][0] & LMP_HOST_SSP)
+#define lmp_host_le_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE))
+#define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR))
+
+/* returns true if at least one AMP active */
+static inline bool hci_amp_capable(void)
+{
+ struct hci_dev *hdev;
+ bool ret = false;
+
+ read_lock(&hci_dev_list_lock);
+ list_for_each_entry(hdev, &hci_dev_list, list)
+ if (hdev->amp_type == HCI_AMP &&
+ test_bit(HCI_UP, &hdev->flags))
+ ret = true;
+ read_unlock(&hci_dev_list_lock);
+
+ return ret;
+}
/* ----- HCI protocols ----- */
-struct hci_proto {
- char *name;
- unsigned int id;
- unsigned long flags;
+#define HCI_PROTO_DEFER 0x01
- void *priv;
-
- int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
- int (*connect_cfm) (struct hci_conn *conn, __u8 status);
- int (*disconn_ind) (struct hci_conn *conn);
- int (*disconn_cfm) (struct hci_conn *conn, __u8 reason,
- __u8 is_process);
- int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
- int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb);
- int (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt);
- int (*create_cfm) (struct hci_chan *chan, __u8 status);
- int (*modify_cfm) (struct hci_chan *chan, __u8 status);
- int (*destroy_cfm) (struct hci_chan *chan, __u8 status);
-};
-
-static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
+static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ __u8 type, __u8 *flags)
{
- register struct hci_proto *hp;
- int mask = 0;
+ switch (type) {
+ case ACL_LINK:
+ return l2cap_connect_ind(hdev, bdaddr);
- hp = hci_proto[HCI_PROTO_L2CAP];
- if (hp && hp->connect_ind)
- mask |= hp->connect_ind(hdev, bdaddr, type);
+ case SCO_LINK:
+ case ESCO_LINK:
+ return sco_connect_ind(hdev, bdaddr, flags);
- hp = hci_proto[HCI_PROTO_SCO];
- if (hp && hp->connect_ind)
- mask |= hp->connect_ind(hdev, bdaddr, type);
-
- return mask;
+ default:
+ BT_ERR("unknown link type %d", type);
+ return -EINVAL;
+ }
}
static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
{
- register struct hci_proto *hp;
+ switch (conn->type) {
+ case ACL_LINK:
+ case LE_LINK:
+ l2cap_connect_cfm(conn, status);
+ break;
- hp = hci_proto[HCI_PROTO_L2CAP];
- if (hp && hp->connect_cfm)
- hp->connect_cfm(conn, status);
+ case SCO_LINK:
+ case ESCO_LINK:
+ sco_connect_cfm(conn, status);
+ break;
- hp = hci_proto[HCI_PROTO_SCO];
- if (hp && hp->connect_cfm)
- hp->connect_cfm(conn, status);
+ default:
+ BT_ERR("unknown link type %d", conn->type);
+ break;
+ }
if (conn->connect_cfm_cb)
conn->connect_cfm_cb(conn, status);
@@ -814,32 +874,33 @@
static inline int hci_proto_disconn_ind(struct hci_conn *conn)
{
- register struct hci_proto *hp;
- int reason = 0x13;
+ if (conn->type != ACL_LINK && conn->type != LE_LINK)
+ return HCI_ERROR_REMOTE_USER_TERM;
- hp = hci_proto[HCI_PROTO_L2CAP];
- if (hp && hp->disconn_ind)
- reason = hp->disconn_ind(conn);
-
- hp = hci_proto[HCI_PROTO_SCO];
- if (hp && hp->disconn_ind)
- reason = hp->disconn_ind(conn);
-
- return reason;
+ return l2cap_disconn_ind(conn);
}
-static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason,
- __u8 is_process)
+static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
{
- register struct hci_proto *hp;
+ switch (conn->type) {
+ case ACL_LINK:
+ case LE_LINK:
+ l2cap_disconn_cfm(conn, reason);
+ break;
- hp = hci_proto[HCI_PROTO_L2CAP];
- if (hp && hp->disconn_cfm)
- hp->disconn_cfm(conn, reason, is_process);
+ case SCO_LINK:
+ case ESCO_LINK:
+ sco_disconn_cfm(conn, reason);
+ break;
- hp = hci_proto[HCI_PROTO_SCO];
- if (hp && hp->disconn_cfm)
- hp->disconn_cfm(conn, reason, is_process);
+ /* L2CAP would be handled for BREDR chan */
+ case AMP_LINK:
+ break;
+
+ default:
+ BT_ERR("unknown link type %d", conn->type);
+ break;
+ }
if (conn->disconn_cfm_cb)
conn->disconn_cfm_cb(conn, reason);
@@ -847,234 +908,277 @@
static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
{
- register struct hci_proto *hp;
__u8 encrypt;
- if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
+ if (conn->type != ACL_LINK && conn->type != LE_LINK)
+ return;
+
+ if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
return;
encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
-
- hp = hci_proto[HCI_PROTO_L2CAP];
- if (hp && hp->security_cfm)
- hp->security_cfm(conn, status, encrypt);
-
- hp = hci_proto[HCI_PROTO_SCO];
- if (hp && hp->security_cfm)
- hp->security_cfm(conn, status, encrypt);
+ l2cap_security_cfm(conn, status, encrypt);
if (conn->security_cfm_cb)
conn->security_cfm_cb(conn, status);
}
-static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encrypt)
+static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status,
+ __u8 encrypt)
{
- register struct hci_proto *hp;
+ if (conn->type != ACL_LINK && conn->type != LE_LINK)
+ return;
- hp = hci_proto[HCI_PROTO_L2CAP];
- if (hp && hp->security_cfm)
- hp->security_cfm(conn, status, encrypt);
-
- hp = hci_proto[HCI_PROTO_SCO];
- if (hp && hp->security_cfm)
- hp->security_cfm(conn, status, encrypt);
+ l2cap_security_cfm(conn, status, encrypt);
if (conn->security_cfm_cb)
conn->security_cfm_cb(conn, status);
}
-static inline void hci_proto_create_cfm(struct hci_chan *chan, __u8 status)
-{
- register struct hci_proto *hp;
-
- hp = hci_proto[HCI_PROTO_L2CAP];
- if (hp && hp->create_cfm)
- hp->create_cfm(chan, status);
-}
-
-static inline void hci_proto_modify_cfm(struct hci_chan *chan, __u8 status)
-{
- register struct hci_proto *hp;
-
- hp = hci_proto[HCI_PROTO_L2CAP];
- if (hp && hp->modify_cfm)
- hp->modify_cfm(chan, status);
-}
-
-static inline void hci_proto_destroy_cfm(struct hci_chan *chan, __u8 status)
-{
- register struct hci_proto *hp;
-
- hp = hci_proto[HCI_PROTO_L2CAP];
- if (hp && hp->destroy_cfm)
- hp->destroy_cfm(chan, status);
-}
-
-int hci_register_proto(struct hci_proto *hproto);
-int hci_unregister_proto(struct hci_proto *hproto);
-
/* ----- HCI callbacks ----- */
struct hci_cb {
struct list_head list;
char *name;
- void (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt);
+ void (*security_cfm) (struct hci_conn *conn, __u8 status,
+ __u8 encrypt);
void (*key_change_cfm) (struct hci_conn *conn, __u8 status);
void (*role_switch_cfm) (struct hci_conn *conn, __u8 status, __u8 role);
};
static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
{
- struct list_head *p;
+ struct hci_cb *cb;
__u8 encrypt;
hci_proto_auth_cfm(conn, status);
- if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
+ if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
return;
encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
- read_lock_bh(&hci_cb_list_lock);
- list_for_each(p, &hci_cb_list) {
- struct hci_cb *cb = list_entry(p, struct hci_cb, list);
+ read_lock(&hci_cb_list_lock);
+ list_for_each_entry(cb, &hci_cb_list, list) {
if (cb->security_cfm)
cb->security_cfm(conn, status, encrypt);
}
- read_unlock_bh(&hci_cb_list_lock);
+ read_unlock(&hci_cb_list_lock);
}
-static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encrypt)
+static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
+ __u8 encrypt)
{
- struct list_head *p;
+ struct hci_cb *cb;
if (conn->sec_level == BT_SECURITY_SDP)
conn->sec_level = BT_SECURITY_LOW;
- if (!status && encrypt && conn->pending_sec_level > conn->sec_level)
+ if (conn->pending_sec_level > conn->sec_level)
conn->sec_level = conn->pending_sec_level;
hci_proto_encrypt_cfm(conn, status, encrypt);
- read_lock_bh(&hci_cb_list_lock);
- list_for_each(p, &hci_cb_list) {
- struct hci_cb *cb = list_entry(p, struct hci_cb, list);
+ read_lock(&hci_cb_list_lock);
+ list_for_each_entry(cb, &hci_cb_list, list) {
if (cb->security_cfm)
cb->security_cfm(conn, status, encrypt);
}
- read_unlock_bh(&hci_cb_list_lock);
+ read_unlock(&hci_cb_list_lock);
}
static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status)
{
- struct list_head *p;
+ struct hci_cb *cb;
- read_lock_bh(&hci_cb_list_lock);
- list_for_each(p, &hci_cb_list) {
- struct hci_cb *cb = list_entry(p, struct hci_cb, list);
+ read_lock(&hci_cb_list_lock);
+ list_for_each_entry(cb, &hci_cb_list, list) {
if (cb->key_change_cfm)
cb->key_change_cfm(conn, status);
}
- read_unlock_bh(&hci_cb_list_lock);
+ read_unlock(&hci_cb_list_lock);
}
-static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, __u8 role)
+static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
+ __u8 role)
{
- struct list_head *p;
+ struct hci_cb *cb;
- read_lock_bh(&hci_cb_list_lock);
- list_for_each(p, &hci_cb_list) {
- struct hci_cb *cb = list_entry(p, struct hci_cb, list);
+ read_lock(&hci_cb_list_lock);
+ list_for_each_entry(cb, &hci_cb_list, list) {
if (cb->role_switch_cfm)
cb->role_switch_cfm(conn, status, role);
}
- read_unlock_bh(&hci_cb_list_lock);
+ read_unlock(&hci_cb_list_lock);
+}
+
+static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type)
+{
+ size_t parsed = 0;
+
+ if (data_len < 2)
+ return false;
+
+ while (parsed < data_len - 1) {
+ u8 field_len = data[0];
+
+ if (field_len == 0)
+ break;
+
+ parsed += field_len + 1;
+
+ if (parsed > data_len)
+ break;
+
+ if (data[1] == type)
+ return true;
+
+ data += field_len + 1;
+ }
+
+ return false;
+}
+
+static inline size_t eir_get_length(u8 *eir, size_t eir_len)
+{
+ size_t parsed = 0;
+
+ while (parsed < eir_len) {
+ u8 field_len = eir[0];
+
+ if (field_len == 0)
+ return parsed;
+
+ parsed += field_len + 1;
+ eir += field_len + 1;
+ }
+
+ return eir_len;
+}
+
+static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
+ u8 data_len)
+{
+ eir[eir_len++] = sizeof(type) + data_len;
+ eir[eir_len++] = type;
+ memcpy(&eir[eir_len], data, data_len);
+ eir_len += data_len;
+
+ return eir_len;
}
int hci_register_cb(struct hci_cb *hcb);
int hci_unregister_cb(struct hci_cb *hcb);
-int hci_register_notifier(struct notifier_block *nb);
-int hci_unregister_notifier(struct notifier_block *nb);
+struct hci_request {
+ struct hci_dev *hdev;
+ struct sk_buff_head cmd_q;
-/* AMP Manager event callbacks */
-struct amp_mgr_cb {
- struct list_head list;
- void (*amp_cmd_complete_event) (struct hci_dev *hdev, __u16 opcode,
- struct sk_buff *skb);
- void (*amp_cmd_status_event) (struct hci_dev *hdev, __u16 opcode,
- __u8 status);
- void (*amp_event) (struct hci_dev *hdev, __u8 ev_code,
- struct sk_buff *skb);
+ /* If something goes wrong when building the HCI request, the error
+ * value is stored in this field.
+ */
+ int err;
};
-void hci_amp_cmd_complete(struct hci_dev *hdev, __u16 opcode,
- struct sk_buff *skb);
-void hci_amp_cmd_status(struct hci_dev *hdev, __u16 opcode, __u8 status);
-void hci_amp_event_packet(struct hci_dev *hdev, __u8 ev_code,
- struct sk_buff *skb);
+void hci_req_init(struct hci_request *req, struct hci_dev *hdev);
+int hci_req_run(struct hci_request *req, hci_req_complete_t complete);
+void hci_req_add(struct hci_request *req, u16 opcode, u32 plen,
+ const void *param);
+void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen,
+ const void *param, u8 event);
+void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status);
-int hci_register_amp(struct amp_mgr_cb *acb);
-int hci_unregister_amp(struct amp_mgr_cb *acb);
+struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
+ const void *param, u32 timeout);
+struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
+ const void *param, u8 event, u32 timeout);
-int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
-void hci_send_acl(struct hci_conn *conn, struct hci_chan *chan,
- struct sk_buff *skb, __u16 flags);
+int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
+ const void *param);
+void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
-void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
-
/* ----- HCI Sockets ----- */
-void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
- struct sock *skip_sk);
+void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
+void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk);
+void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb);
+
+void hci_sock_dev_event(struct hci_dev *hdev, int event);
/* Management interface */
-int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
-int mgmt_index_added(u16 index);
-int mgmt_index_removed(u16 index);
-int mgmt_powered(u16 index, u8 powered);
-int mgmt_discoverable(u16 index, u8 discoverable);
-int mgmt_connectable(u16 index, u8 connectable);
-int mgmt_new_key(u16 index, struct link_key *key, u8 bonded);
-int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le);
-int mgmt_le_conn_params(u16 index, bdaddr_t *bdaddr, u16 interval,
- u16 latency, u16 timeout);
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr, u8 reason);
-int mgmt_disconnect_failed(u16 index);
-int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr);
-int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_user_confirm_request(u16 index, u8 event, bdaddr_t *bdaddr,
- __le32 value);
-int mgmt_user_oob_request(u16 index, bdaddr_t *bdaddr);
-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 type, u8 le,
- u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir);
-void mgmt_read_rssi_complete(u16 index, s8 rssi, bdaddr_t *bdaddr,
- u16 handle, u8 status);
-int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name);
-void mgmt_inquiry_started(u16 index);
-void mgmt_inquiry_complete_evt(u16 index, u8 status);
-void mgmt_disco_timeout(unsigned long data);
-void mgmt_disco_le_timeout(unsigned long data);
-int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status);
+#define DISCOV_TYPE_BREDR (BIT(BDADDR_BREDR))
+#define DISCOV_TYPE_LE (BIT(BDADDR_LE_PUBLIC) | \
+ BIT(BDADDR_LE_RANDOM))
+#define DISCOV_TYPE_INTERLEAVED (BIT(BDADDR_BREDR) | \
+ BIT(BDADDR_LE_PUBLIC) | \
+ BIT(BDADDR_LE_RANDOM))
-/* LE SMP Management interface */
-int le_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, void *cp);
-int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3]);
-int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf,
- u16 sub_ver);
-int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8]);
+int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
+int mgmt_index_added(struct hci_dev *hdev);
+int mgmt_index_removed(struct hci_dev *hdev);
+int mgmt_set_powered_failed(struct hci_dev *hdev, int err);
+int mgmt_powered(struct hci_dev *hdev, u8 powered);
+int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable);
+int mgmt_connectable(struct hci_dev *hdev, u8 connectable);
+int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status);
+int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
+ bool persistent);
+int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+ u8 addr_type, u32 flags, u8 *name, u8 name_len,
+ u8 *dev_class);
+int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 link_type, u8 addr_type, u8 reason);
+int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 link_type, u8 addr_type, u8 status);
+int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+ u8 addr_type, u8 status);
+int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure);
+int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 status);
+int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 status);
+int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 link_type, u8 addr_type, __le32 value,
+ u8 confirm_hint);
+int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 link_type, u8 addr_type, u8 status);
+int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 link_type, u8 addr_type, u8 status);
+int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 link_type, u8 addr_type);
+int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 link_type, u8 addr_type, u8 status);
+int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 link_type, u8 addr_type, u8 status);
+int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 link_type, u8 addr_type, u32 passkey,
+ u8 entered);
+int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+ u8 addr_type, u8 status);
+int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
+int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
+int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
+ u8 status);
+int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
+int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
+ u8 *randomizer, u8 status);
+int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
+int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+ u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name,
+ u8 ssp, u8 *eir, u16 eir_len);
+int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+ u8 addr_type, s8 rssi, u8 *name, u8 name_len);
+int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status);
+int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status);
+int mgmt_discovering(struct hci_dev *hdev, u8 discovering);
+int mgmt_interleaved_discovery(struct hci_dev *hdev);
+int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+bool mgmt_valid_hdev(struct hci_dev *hdev);
+int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent);
/* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk)
@@ -1104,15 +1208,18 @@
#define hci_req_lock(d) mutex_lock(&d->req_lock)
#define hci_req_unlock(d) mutex_unlock(&d->req_lock)
-void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result);
+void hci_update_ad(struct hci_request *req);
void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
u16 latency, u16 to_multiplier);
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
__u8 ltk[16]);
-void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]);
-void hci_le_ltk_neg_reply(struct hci_conn *conn);
+int hci_do_inquiry(struct hci_dev *hdev, u8 length);
+int hci_cancel_inquiry(struct hci_dev *hdev);
+int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
+ int timeout);
+int hci_cancel_le_scan(struct hci_dev *hdev);
-void hci_read_rssi(struct hci_conn *conn);
+u8 bdaddr_to_le(u8 bdaddr_type);
#endif /* __HCI_CORE_H */
diff --git a/include/net/bluetooth/hci_mon.h b/include/net/bluetooth/hci_mon.h
new file mode 100644
index 0000000..77d1e57
--- /dev/null
+++ b/include/net/bluetooth/hci_mon.h
@@ -0,0 +1,51 @@
+/*
+ BlueZ - Bluetooth protocol stack for Linux
+
+ Copyright (C) 2011-2012 Intel Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation;
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
+ SOFTWARE IS DISCLAIMED.
+*/
+
+#ifndef __HCI_MON_H
+#define __HCI_MON_H
+
+struct hci_mon_hdr {
+ __le16 opcode;
+ __le16 index;
+ __le16 len;
+} __packed;
+#define HCI_MON_HDR_SIZE 6
+
+#define HCI_MON_NEW_INDEX 0
+#define HCI_MON_DEL_INDEX 1
+#define HCI_MON_COMMAND_PKT 2
+#define HCI_MON_EVENT_PKT 3
+#define HCI_MON_ACL_TX_PKT 4
+#define HCI_MON_ACL_RX_PKT 5
+#define HCI_MON_SCO_TX_PKT 6
+#define HCI_MON_SCO_RX_PKT 7
+
+struct hci_mon_new_index {
+ __u8 type;
+ __u8 bus;
+ bdaddr_t bdaddr;
+ char name[8];
+} __packed;
+#define HCI_MON_NEW_INDEX_SIZE 16
+
+#endif /* __HCI_MON_H */
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index b1ee41a..fb94cf1 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved.
+ Copyright (C) 2000-2001 Qualcomm Incorporated
Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Copyright (C) 2010 Google Inc.
@@ -27,39 +27,43 @@
#ifndef __L2CAP_H
#define __L2CAP_H
+#include <asm/unaligned.h>
+
/* L2CAP defaults */
#define L2CAP_DEFAULT_MTU 672
#define L2CAP_DEFAULT_MIN_MTU 48
-#define L2CAP_DEFAULT_MAX_SDU_SIZE 0xffff
-#define L2CAP_DEFAULT_FLUSH_TO 0xffff
-#define L2CAP_MAX_FLUSH_TO 0x7ff
+#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
+#define L2CAP_EFS_DEFAULT_FLUSH_TO 0xFFFFFFFF
#define L2CAP_DEFAULT_TX_WINDOW 63
+#define L2CAP_DEFAULT_EXT_WINDOW 0x3FFF
#define L2CAP_DEFAULT_MAX_TX 3
#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */
#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
-#define L2CAP_DEFAULT_MAX_PDU_SIZE 1482 /* Sized for AMP or BR/EDR */
+#define L2CAP_DEFAULT_MAX_PDU_SIZE 1492 /* Sized for AMP packet */
#define L2CAP_DEFAULT_ACK_TO 200
+#define L2CAP_DEFAULT_MAX_SDU_SIZE 0xFFFF
+#define L2CAP_DEFAULT_SDU_ITIME 0xFFFFFFFF
+#define L2CAP_DEFAULT_ACC_LAT 0xFFFFFFFF
#define L2CAP_BREDR_MAX_PAYLOAD 1019 /* 3-DH5 packet */
-#define L2CAP_MAX_ERTM_QUEUED 5
-#define L2CAP_MIN_ERTM_QUEUED 2
+#define L2CAP_LE_MIN_MTU 23
+
+#define L2CAP_DISC_TIMEOUT msecs_to_jiffies(100)
+#define L2CAP_DISC_REJ_TIMEOUT msecs_to_jiffies(5000)
+#define L2CAP_ENC_TIMEOUT msecs_to_jiffies(5000)
+#define L2CAP_CONN_TIMEOUT msecs_to_jiffies(40000)
+#define L2CAP_INFO_TIMEOUT msecs_to_jiffies(4000)
+#define L2CAP_MOVE_TIMEOUT msecs_to_jiffies(4000)
+#define L2CAP_MOVE_ERTX_TIMEOUT msecs_to_jiffies(60000)
#define L2CAP_A2MP_DEFAULT_MTU 670
-#define L2CAP_TX_WIN_MAX_ENHANCED 0x3f
-#define L2CAP_TX_WIN_MAX_EXTENDED 0x3fff
-#define L2CAP_LE_DEFAULT_MTU 23
-
-#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */
-#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */
-#define L2CAP_MOVE_TIMEOUT (4*HZ) /* 4 seconds */
-#define L2CAP_MOVE_ERTX_TIMEOUT (60*HZ) /* 60 seconds */
-
/* L2CAP socket address */
struct sockaddr_l2 {
sa_family_t l2_family;
__le16 l2_psm;
bdaddr_t l2_bdaddr;
__le16 l2_cid;
+ __u8 l2_bdaddr_type;
};
/* L2CAP socket options */
@@ -87,35 +91,36 @@
#define L2CAP_LM_TRUSTED 0x0008
#define L2CAP_LM_RELIABLE 0x0010
#define L2CAP_LM_SECURE 0x0020
-#define L2CAP_LM_FLUSHABLE 0x0040
/* L2CAP command codes */
-#define L2CAP_COMMAND_REJ 0x01
-#define L2CAP_CONN_REQ 0x02
-#define L2CAP_CONN_RSP 0x03
-#define L2CAP_CONF_REQ 0x04
-#define L2CAP_CONF_RSP 0x05
-#define L2CAP_DISCONN_REQ 0x06
-#define L2CAP_DISCONN_RSP 0x07
-#define L2CAP_ECHO_REQ 0x08
-#define L2CAP_ECHO_RSP 0x09
-#define L2CAP_INFO_REQ 0x0a
-#define L2CAP_INFO_RSP 0x0b
+#define L2CAP_COMMAND_REJ 0x01
+#define L2CAP_CONN_REQ 0x02
+#define L2CAP_CONN_RSP 0x03
+#define L2CAP_CONF_REQ 0x04
+#define L2CAP_CONF_RSP 0x05
+#define L2CAP_DISCONN_REQ 0x06
+#define L2CAP_DISCONN_RSP 0x07
+#define L2CAP_ECHO_REQ 0x08
+#define L2CAP_ECHO_RSP 0x09
+#define L2CAP_INFO_REQ 0x0a
+#define L2CAP_INFO_RSP 0x0b
#define L2CAP_CREATE_CHAN_REQ 0x0c
#define L2CAP_CREATE_CHAN_RSP 0x0d
-#define L2CAP_MOVE_CHAN_REQ 0x0e
-#define L2CAP_MOVE_CHAN_RSP 0x0f
-#define L2CAP_MOVE_CHAN_CFM 0x10
+#define L2CAP_MOVE_CHAN_REQ 0x0e
+#define L2CAP_MOVE_CHAN_RSP 0x0f
+#define L2CAP_MOVE_CHAN_CFM 0x10
#define L2CAP_MOVE_CHAN_CFM_RSP 0x11
#define L2CAP_CONN_PARAM_UPDATE_REQ 0x12
#define L2CAP_CONN_PARAM_UPDATE_RSP 0x13
-/* L2CAP feature mask */
+/* L2CAP extended feature mask */
#define L2CAP_FEAT_FLOWCTL 0x00000001
#define L2CAP_FEAT_RETRANS 0x00000002
+#define L2CAP_FEAT_BIDIR_QOS 0x00000004
#define L2CAP_FEAT_ERTM 0x00000008
#define L2CAP_FEAT_STREAMING 0x00000010
#define L2CAP_FEAT_FCS 0x00000020
+#define L2CAP_FEAT_EXT_FLOW 0x00000040
#define L2CAP_FEAT_FIXED_CHAN 0x00000080
#define L2CAP_FEAT_EXT_WINDOW 0x00000100
#define L2CAP_FEAT_UCD 0x00000200
@@ -128,52 +133,57 @@
#define L2CAP_FC_L2CAP 0x02
#define L2CAP_FC_A2MP 0x08
-/* L2CAP Control Field */
-#define L2CAP_CTRL_SAR 0xC000
-#define L2CAP_CTRL_REQSEQ 0x3F00
-#define L2CAP_CTRL_TXSEQ 0x007E
-#define L2CAP_CTRL_FINAL 0x0080
-#define L2CAP_CTRL_POLL 0x0010
-#define L2CAP_CTRL_SUPERVISE 0x000C
-#define L2CAP_CTRL_FRAME_TYPE 0x0001 /* I- or S-Frame */
+/* L2CAP Control Field bit masks */
+#define L2CAP_CTRL_SAR 0xC000
+#define L2CAP_CTRL_REQSEQ 0x3F00
+#define L2CAP_CTRL_TXSEQ 0x007E
+#define L2CAP_CTRL_SUPERVISE 0x000C
-#define L2CAP_CTRL_TXSEQ_SHIFT 1
-#define L2CAP_CTRL_SUPERVISE_SHIFT 2
-#define L2CAP_CTRL_POLL_SHIFT 4
-#define L2CAP_CTRL_FINAL_SHIFT 7
-#define L2CAP_CTRL_REQSEQ_SHIFT 8
-#define L2CAP_CTRL_SAR_SHIFT 14
+#define L2CAP_CTRL_RETRANS 0x0080
+#define L2CAP_CTRL_FINAL 0x0080
+#define L2CAP_CTRL_POLL 0x0010
+#define L2CAP_CTRL_FRAME_TYPE 0x0001 /* I- or S-Frame */
-#define L2CAP_EXT_CTRL_SAR 0x00030000
-#define L2CAP_EXT_CTRL_REQSEQ 0x0000FFFC
-#define L2CAP_EXT_CTRL_TXSEQ 0xFFFC0000
-#define L2CAP_EXT_CTRL_FINAL 0x00000002
-#define L2CAP_EXT_CTRL_POLL 0x00040000
-#define L2CAP_EXT_CTRL_SUPERVISE 0x00030000
-#define L2CAP_EXT_CTRL_FRAME_TYPE 0x00000001 /* I- or S-Frame */
+#define L2CAP_CTRL_TXSEQ_SHIFT 1
+#define L2CAP_CTRL_SUPER_SHIFT 2
+#define L2CAP_CTRL_POLL_SHIFT 4
+#define L2CAP_CTRL_FINAL_SHIFT 7
+#define L2CAP_CTRL_REQSEQ_SHIFT 8
+#define L2CAP_CTRL_SAR_SHIFT 14
-#define L2CAP_EXT_CTRL_FINAL_SHIFT 1
-#define L2CAP_EXT_CTRL_REQSEQ_SHIFT 2
-#define L2CAP_EXT_CTRL_SAR_SHIFT 16
-#define L2CAP_EXT_CTRL_SUPERVISE_SHIFT 16
-#define L2CAP_EXT_CTRL_POLL_SHIFT 18
-#define L2CAP_EXT_CTRL_TXSEQ_SHIFT 18
+/* L2CAP Extended Control Field bit mask */
+#define L2CAP_EXT_CTRL_TXSEQ 0xFFFC0000
+#define L2CAP_EXT_CTRL_SAR 0x00030000
+#define L2CAP_EXT_CTRL_SUPERVISE 0x00030000
+#define L2CAP_EXT_CTRL_REQSEQ 0x0000FFFC
-/* L2CAP Supervisory Frame Types */
-#define L2CAP_SFRAME_RR 0x00
-#define L2CAP_SFRAME_REJ 0x01
-#define L2CAP_SFRAME_RNR 0x02
-#define L2CAP_SFRAME_SREJ 0x03
+#define L2CAP_EXT_CTRL_POLL 0x00040000
+#define L2CAP_EXT_CTRL_FINAL 0x00000002
+#define L2CAP_EXT_CTRL_FRAME_TYPE 0x00000001 /* I- or S-Frame */
+
+#define L2CAP_EXT_CTRL_FINAL_SHIFT 1
+#define L2CAP_EXT_CTRL_REQSEQ_SHIFT 2
+#define L2CAP_EXT_CTRL_SAR_SHIFT 16
+#define L2CAP_EXT_CTRL_SUPER_SHIFT 16
+#define L2CAP_EXT_CTRL_POLL_SHIFT 18
+#define L2CAP_EXT_CTRL_TXSEQ_SHIFT 18
+
+/* L2CAP Supervisory Function */
+#define L2CAP_SUPER_RR 0x00
+#define L2CAP_SUPER_REJ 0x01
+#define L2CAP_SUPER_RNR 0x02
+#define L2CAP_SUPER_SREJ 0x03
/* L2CAP Segmentation and Reassembly */
-#define L2CAP_SAR_UNSEGMENTED 0x00
-#define L2CAP_SAR_START 0x01
-#define L2CAP_SAR_END 0x02
-#define L2CAP_SAR_CONTINUE 0x03
+#define L2CAP_SAR_UNSEGMENTED 0x00
+#define L2CAP_SAR_START 0x01
+#define L2CAP_SAR_END 0x02
+#define L2CAP_SAR_CONTINUE 0x03
-/* L2CAP ERTM / Streaming extra field lengths */
-#define L2CAP_SDULEN_SIZE 2
-#define L2CAP_FCS_SIZE 2
+/* L2CAP Command rej. reasons */
+#define L2CAP_REJ_NOT_UNDERSTOOD 0x0000
+#define L2CAP_REJ_MTU_EXCEEDED 0x0001
+#define L2CAP_REJ_INVALID_CID 0x0002
/* L2CAP structures */
struct l2cap_hdr {
@@ -181,8 +191,14 @@
__le16 cid;
} __packed;
#define L2CAP_HDR_SIZE 4
-#define L2CAP_ENHANCED_HDR_SIZE 6
-#define L2CAP_EXTENDED_HDR_SIZE 8
+#define L2CAP_ENH_HDR_SIZE 6
+#define L2CAP_EXT_HDR_SIZE 8
+
+#define L2CAP_FCS_SIZE 2
+#define L2CAP_SDULEN_SIZE 2
+#define L2CAP_PSMLEN_SIZE 2
+#define L2CAP_ENH_CTRL_SIZE 2
+#define L2CAP_EXT_CTRL_SIZE 4
struct l2cap_cmd_hdr {
__u8 code;
@@ -191,10 +207,21 @@
} __packed;
#define L2CAP_CMD_HDR_SIZE 4
-struct l2cap_cmd_rej {
+struct l2cap_cmd_rej_unk {
__le16 reason;
} __packed;
+struct l2cap_cmd_rej_mtu {
+ __le16 reason;
+ __le16 max_mtu;
+} __packed;
+
+struct l2cap_cmd_rej_cid {
+ __le16 reason;
+ __le16 scid;
+ __le16 dcid;
+} __packed;
+
struct l2cap_conn_req {
__le16 psm;
__le16 scid;
@@ -207,6 +234,10 @@
__le16 status;
} __packed;
+/* protocol/service multiplexer (PSM) */
+#define L2CAP_PSM_SDP 0x0001
+#define L2CAP_PSM_RFCOMM 0x0003
+
/* channel indentifier */
#define L2CAP_CID_SIGNALING 0x0001
#define L2CAP_CID_CONN_LESS 0x0002
@@ -217,14 +248,15 @@
#define L2CAP_CID_DYN_START 0x0040
#define L2CAP_CID_DYN_END 0xffff
-/* connect result */
+/* connect/create channel results */
#define L2CAP_CR_SUCCESS 0x0000
#define L2CAP_CR_PEND 0x0001
#define L2CAP_CR_BAD_PSM 0x0002
#define L2CAP_CR_SEC_BLOCK 0x0003
#define L2CAP_CR_NO_MEM 0x0004
+#define L2CAP_CR_BAD_AMP 0x0005
-/* connect status */
+/* connect/create channel status */
#define L2CAP_CS_NO_INFO 0x0000
#define L2CAP_CS_AUTHEN_PEND 0x0001
#define L2CAP_CS_AUTHOR_PEND 0x0002
@@ -247,7 +279,10 @@
#define L2CAP_CONF_REJECT 0x0002
#define L2CAP_CONF_UNKNOWN 0x0003
#define L2CAP_CONF_PENDING 0x0004
-#define L2CAP_CONF_FLOW_SPEC_REJECT 0x0005
+#define L2CAP_CONF_EFS_REJECT 0x0005
+
+/* configuration req/rsp continuation flag */
+#define L2CAP_CONF_FLAG_CONTINUATION 0x0001
struct l2cap_conf_opt {
__u8 type;
@@ -264,13 +299,8 @@
#define L2CAP_CONF_QOS 0x03
#define L2CAP_CONF_RFC 0x04
#define L2CAP_CONF_FCS 0x05
-#define L2CAP_CONF_EXT_FS 0x06
-#define L2CAP_CONF_EXT_WINDOW 0x07
-
-/* QOS Service type */
-#define L2CAP_SERVICE_NO_TRAFFIC 0x00
-#define L2CAP_SERVICE_BEST_EFFORT 0x01
-#define L2CAP_SERVICE_GUARANTEED 0x02
+#define L2CAP_CONF_EFS 0x06
+#define L2CAP_CONF_EWS 0x07
#define L2CAP_CONF_MAX_SIZE 22
@@ -283,26 +313,27 @@
__le16 max_pdu_size;
} __packed;
-struct l2cap_conf_ext_fs {
- __u8 id;
- __u8 type;
- __le16 max_sdu;
- __le32 sdu_arr_time;
- __le32 acc_latency;
- __le32 flush_to;
-} __packed;
-
-struct l2cap_conf_prm {
- __u8 fcs;
- __le32 flush_to;
-};
-
#define L2CAP_MODE_BASIC 0x00
#define L2CAP_MODE_RETRANS 0x01
#define L2CAP_MODE_FLOWCTL 0x02
#define L2CAP_MODE_ERTM 0x03
#define L2CAP_MODE_STREAMING 0x04
+struct l2cap_conf_efs {
+ __u8 id;
+ __u8 stype;
+ __le16 msdu;
+ __le32 sdu_itime;
+ __le32 acc_lat;
+ __le32 flush_to;
+} __packed;
+
+#define L2CAP_SERV_NOTRAFIC 0x00
+#define L2CAP_SERV_BESTEFFORT 0x01
+#define L2CAP_SERV_GUARANTEED 0x02
+
+#define L2CAP_BESTEFFORT_ID 0x01
+
struct l2cap_disconn_req {
__le16 dcid;
__le16 scid;
@@ -327,83 +358,53 @@
__le16 psm;
__le16 scid;
__u8 amp_id;
-} __attribute__ ((packed));
+} __packed;
struct l2cap_create_chan_rsp {
__le16 dcid;
__le16 scid;
__le16 result;
__le16 status;
-} __attribute__ ((packed));
-
-#define L2CAP_CREATE_CHAN_SUCCESS (0x0000)
-#define L2CAP_CREATE_CHAN_PENDING (0x0001)
-#define L2CAP_CREATE_CHAN_REFUSED_PSM (0x0002)
-#define L2CAP_CREATE_CHAN_REFUSED_SECURITY (0x0003)
-#define L2CAP_CREATE_CHAN_REFUSED_RESOURCES (0x0004)
-#define L2CAP_CREATE_CHAN_REFUSED_CONTROLLER (0x0005)
-
-#define L2CAP_CREATE_CHAN_STATUS_NONE (0x0000)
-#define L2CAP_CREATE_CHAN_STATUS_AUTHENTICATION (0x0001)
-#define L2CAP_CREATE_CHAN_STATUS_AUTHORIZATION (0x0002)
+} __packed;
struct l2cap_move_chan_req {
__le16 icid;
__u8 dest_amp_id;
-} __attribute__ ((packed));
+} __packed;
struct l2cap_move_chan_rsp {
__le16 icid;
__le16 result;
-} __attribute__ ((packed));
+} __packed;
-#define L2CAP_MOVE_CHAN_SUCCESS (0x0000)
-#define L2CAP_MOVE_CHAN_PENDING (0x0001)
-#define L2CAP_MOVE_CHAN_REFUSED_CONTROLLER (0x0002)
-#define L2CAP_MOVE_CHAN_REFUSED_SAME_ID (0x0003)
-#define L2CAP_MOVE_CHAN_REFUSED_CONFIG (0x0004)
-#define L2CAP_MOVE_CHAN_REFUSED_COLLISION (0x0005)
-#define L2CAP_MOVE_CHAN_REFUSED_NOT_ALLOWED (0x0006)
+#define L2CAP_MR_SUCCESS 0x0000
+#define L2CAP_MR_PEND 0x0001
+#define L2CAP_MR_BAD_ID 0x0002
+#define L2CAP_MR_SAME_ID 0x0003
+#define L2CAP_MR_NOT_SUPP 0x0004
+#define L2CAP_MR_COLLISION 0x0005
+#define L2CAP_MR_NOT_ALLOWED 0x0006
struct l2cap_move_chan_cfm {
__le16 icid;
__le16 result;
-} __attribute__ ((packed));
+} __packed;
-#define L2CAP_MOVE_CHAN_CONFIRMED (0x0000)
-#define L2CAP_MOVE_CHAN_UNCONFIRMED (0x0001)
+#define L2CAP_MC_CONFIRMED 0x0000
+#define L2CAP_MC_UNCONFIRMED 0x0001
struct l2cap_move_chan_cfm_rsp {
__le16 icid;
-} __attribute__ ((packed));
-
-struct l2cap_amp_signal_work {
- struct work_struct work;
- struct l2cap_cmd_hdr cmd;
- struct l2cap_conn *conn;
- struct sk_buff *skb;
- u8 *data;
-};
-
-struct l2cap_resegment_work {
- struct work_struct work;
- struct sock *sk;
-};
-
-struct l2cap_logical_link_work {
- struct work_struct work;
- struct hci_chan *chan;
- u8 status;
-};
+} __packed;
/* info type */
-#define L2CAP_IT_CL_MTU 0x0001
-#define L2CAP_IT_FEAT_MASK 0x0002
-#define L2CAP_IT_FIXED_CHAN 0x0003
+#define L2CAP_IT_CL_MTU 0x0001
+#define L2CAP_IT_FEAT_MASK 0x0002
+#define L2CAP_IT_FIXED_CHAN 0x0003
/* info result */
-#define L2CAP_IR_SUCCESS 0x0000
-#define L2CAP_IR_NOTSUPP 0x0001
+#define L2CAP_IR_SUCCESS 0x0000
+#define L2CAP_IR_NOTSUPP 0x0001
struct l2cap_conn_param_update_req {
__le16 min;
@@ -420,64 +421,27 @@
#define L2CAP_CONN_PARAM_ACCEPTED 0x0000
#define L2CAP_CONN_PARAM_REJECTED 0x0001
-/* ----- L2CAP connections ----- */
-struct l2cap_chan_list {
- struct sock *head;
- rwlock_t lock;
-};
-
-struct l2cap_conn {
- struct hci_conn *hcon;
-
- bdaddr_t *dst;
- bdaddr_t *src;
-
- unsigned int mtu;
-
- __u32 feat_mask;
- __u8 fc_mask;
- struct amp_mgr *mgr;
-
- __u8 info_state;
- __u8 info_ident;
-
- struct timer_list info_timer;
-
- spinlock_t lock;
-
- struct sk_buff *rx_skb;
- __u32 rx_len;
- __u8 tx_ident;
-
- __u8 disc_reason;
-
- struct l2cap_chan_list chan_list;
-};
-
-struct sock_del_list {
- struct sock *sk;
- struct list_head list;
-};
-
-#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01
-#define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04
-#define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08
-
-/* ----- L2CAP channel and socket info ----- */
-#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
-#define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue)
-#define SREJ_QUEUE(sk) (&l2cap_pi(sk)->srej_queue)
-
+/* ----- L2CAP channels and connections ----- */
struct l2cap_seq_list {
- __u16 head;
- __u16 tail;
- __u16 size;
- __u16 mask;
- __u16 *list;
+ __u16 head;
+ __u16 tail;
+ __u16 mask;
+ __u16 *list;
};
-struct l2cap_pinfo {
- struct bt_sock bt;
+#define L2CAP_SEQ_LIST_CLEAR 0xFFFF
+#define L2CAP_SEQ_LIST_TAIL 0x8000
+
+struct l2cap_chan {
+ struct sock *sk;
+
+ struct l2cap_conn *conn;
+ struct hci_conn *hs_hcon;
+ struct hci_chan *hs_hchan;
+ struct kref kref;
+
+ __u8 state;
+
__le16 psm;
__u16 dcid;
__u16 scid;
@@ -486,34 +450,42 @@
__u16 omtu;
__u16 flush_to;
__u8 mode;
- __u8 fixed_channel;
- __u8 num_conf_req;
- __u8 num_conf_rsp;
- __u8 incoming;
+ __u8 chan_type;
+ __u8 chan_policy;
- __u8 fcs;
+ __le16 sport;
+
__u8 sec_level;
- __u8 role_switch;
- __u8 force_reliable;
- __u8 flushable;
- __u8 force_active;
+
+ __u8 ident;
__u8 conf_req[64];
__u8 conf_len;
- __u8 conf_ident;
- __u16 conf_state;
- __u8 conn_state;
+ __u8 num_conf_req;
+ __u8 num_conf_rsp;
+
+ __u8 fcs;
+
+ __u16 tx_win;
+ __u16 tx_win_max;
+ __u16 ack_win;
+ __u8 max_tx;
+ __u16 retrans_timeout;
+ __u16 monitor_timeout;
+ __u16 mps;
+
__u8 tx_state;
__u8 rx_state;
- __u8 reconf_state;
- __u8 amp_id;
- __u8 amp_move_id;
- __u8 amp_move_state;
- __u8 amp_move_role;
- __u8 amp_move_cmd_ident;
- __u16 amp_move_reqseq;
- __u16 amp_move_event;
+ unsigned long conf_state;
+ unsigned long conn_state;
+ unsigned long flags;
+
+ __u8 remote_amp_id;
+ __u8 local_amp_id;
+ __u8 move_id;
+ __u8 move_state;
+ __u8 move_role;
__u16 next_tx_seq;
__u16 expected_ack_seq;
@@ -521,203 +493,338 @@
__u16 buffer_seq;
__u16 srej_save_reqseq;
__u16 last_acked_seq;
- __u32 frames_sent;
+ __u16 frames_sent;
__u16 unacked_frames;
__u8 retry_count;
- __u16 srej_queue_next;
__u16 sdu_len;
struct sk_buff *sdu;
struct sk_buff *sdu_last_frag;
- atomic_t ertm_queued;
- __u8 ident;
-
- __u16 tx_win;
- __u16 tx_win_max;
- __u16 ack_win;
- __u8 max_tx;
- __u8 amp_pref;
__u16 remote_tx_win;
__u8 remote_max_tx;
- __u8 extended_control;
- __u16 retrans_timeout;
- __u16 monitor_timeout;
__u16 remote_mps;
- __u16 mps;
- __le16 sport;
+ __u8 local_id;
+ __u8 local_stype;
+ __u16 local_msdu;
+ __u32 local_sdu_itime;
+ __u32 local_acc_lat;
+ __u32 local_flush_to;
- struct delayed_work retrans_work;
- struct delayed_work monitor_work;
- struct delayed_work ack_work;
- struct work_struct tx_work;
- struct sk_buff_head tx_queue;
- struct sk_buff_head srej_queue;
- struct l2cap_seq_list srej_list;
- struct l2cap_seq_list retrans_list;
- struct hci_conn *ampcon;
- struct hci_chan *ampchan;
- struct l2cap_conn *conn;
- struct l2cap_conf_prm local_conf;
- struct l2cap_conf_prm remote_conf;
- struct l2cap_conf_ext_fs local_fs;
- struct l2cap_conf_ext_fs remote_fs;
- struct sock *next_c;
- struct sock *prev_c;
+ __u8 remote_id;
+ __u8 remote_stype;
+ __u16 remote_msdu;
+ __u32 remote_sdu_itime;
+ __u32 remote_acc_lat;
+ __u32 remote_flush_to;
+
+ struct delayed_work chan_timer;
+ struct delayed_work retrans_timer;
+ struct delayed_work monitor_timer;
+ struct delayed_work ack_timer;
+
+ struct sk_buff *tx_send_head;
+ struct sk_buff_head tx_q;
+ struct sk_buff_head srej_q;
+ struct l2cap_seq_list srej_list;
+ struct l2cap_seq_list retrans_list;
+
+ struct list_head list;
+ struct list_head global_l;
+
+ void *data;
+ struct l2cap_ops *ops;
+ struct mutex lock;
};
-#define L2CAP_CONF_REQ_SENT 0x0001
-#define L2CAP_CONF_INPUT_DONE 0x0002
-#define L2CAP_CONF_OUTPUT_DONE 0x0004
-#define L2CAP_CONF_MTU_DONE 0x0008
-#define L2CAP_CONF_MODE_DONE 0x0010
-#define L2CAP_CONF_CONNECT_PEND 0x0020
-#define L2CAP_CONF_NO_FCS_RECV 0x0040
-#define L2CAP_CONF_STATE2_DEVICE 0x0080
-#define L2CAP_CONF_EXT_WIN_RECV 0x0100
-#define L2CAP_CONF_LOCKSTEP 0x0200
-#define L2CAP_CONF_LOCKSTEP_PEND 0x0400
-#define L2CAP_CONF_PEND_SENT 0x0800
-#define L2CAP_CONF_EFS_RECV 0x1000
+struct l2cap_ops {
+ char *name;
+
+ struct l2cap_chan *(*new_connection) (struct l2cap_chan *chan);
+ int (*recv) (struct l2cap_chan * chan,
+ struct sk_buff *skb);
+ void (*teardown) (struct l2cap_chan *chan, int err);
+ void (*close) (struct l2cap_chan *chan);
+ void (*state_change) (struct l2cap_chan *chan,
+ int state);
+ void (*ready) (struct l2cap_chan *chan);
+ void (*defer) (struct l2cap_chan *chan);
+ struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan,
+ unsigned long len, int nb);
+};
+
+struct l2cap_conn {
+ struct hci_conn *hcon;
+ struct hci_chan *hchan;
+
+ bdaddr_t *dst;
+ bdaddr_t *src;
+
+ unsigned int mtu;
+
+ __u32 feat_mask;
+ __u8 fixed_chan_mask;
+
+ __u8 info_state;
+ __u8 info_ident;
+
+ struct delayed_work info_timer;
+
+ spinlock_t lock;
+
+ struct sk_buff *rx_skb;
+ __u32 rx_len;
+ __u8 tx_ident;
+
+ __u8 disc_reason;
+
+ struct delayed_work security_timer;
+ struct smp_chan *smp_chan;
+
+ struct list_head chan_l;
+ struct mutex chan_lock;
+ struct kref ref;
+ struct list_head users;
+};
+
+struct l2cap_user {
+ struct list_head list;
+ int (*probe) (struct l2cap_conn *conn, struct l2cap_user *user);
+ void (*remove) (struct l2cap_conn *conn, struct l2cap_user *user);
+};
+
+#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01
+#define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04
+#define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08
+
+#define L2CAP_CHAN_RAW 1
+#define L2CAP_CHAN_CONN_LESS 2
+#define L2CAP_CHAN_CONN_ORIENTED 3
+#define L2CAP_CHAN_CONN_FIX_A2MP 4
+
+/* ----- L2CAP socket info ----- */
+#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
+
+struct l2cap_pinfo {
+ struct bt_sock bt;
+ struct l2cap_chan *chan;
+ struct sk_buff *rx_busy_skb;
+};
+
+enum {
+ CONF_REQ_SENT,
+ CONF_INPUT_DONE,
+ CONF_OUTPUT_DONE,
+ CONF_MTU_DONE,
+ CONF_MODE_DONE,
+ CONF_CONNECT_PEND,
+ CONF_RECV_NO_FCS,
+ CONF_STATE2_DEVICE,
+ CONF_EWS_RECV,
+ CONF_LOC_CONF_PEND,
+ CONF_REM_CONF_PEND,
+ CONF_NOT_COMPLETE,
+};
#define L2CAP_CONF_MAX_CONF_REQ 2
#define L2CAP_CONF_MAX_CONF_RSP 2
-#define L2CAP_RECONF_NONE 0x00
-#define L2CAP_RECONF_INT 0x01
-#define L2CAP_RECONF_ACC 0x02
+enum {
+ CONN_SREJ_SENT,
+ CONN_WAIT_F,
+ CONN_SREJ_ACT,
+ CONN_SEND_PBIT,
+ CONN_REMOTE_BUSY,
+ CONN_LOCAL_BUSY,
+ CONN_REJ_ACT,
+ CONN_SEND_FBIT,
+ CONN_RNR_SENT,
+};
-#define L2CAP_CONN_SREJ_ACT 0x01
-#define L2CAP_CONN_REJ_ACT 0x02
-#define L2CAP_CONN_REMOTE_BUSY 0x04
-#define L2CAP_CONN_LOCAL_BUSY 0x08
-#define L2CAP_CONN_SEND_FBIT 0x10
-#define L2CAP_CONN_SENT_RNR 0x20
+/* Definitions for flags in l2cap_chan */
+enum {
+ FLAG_ROLE_SWITCH,
+ FLAG_FORCE_ACTIVE,
+ FLAG_FORCE_RELIABLE,
+ FLAG_FLUSHABLE,
+ FLAG_EXT_CTRL,
+ FLAG_EFS_ENABLE,
+};
-#define L2CAP_SEQ_LIST_CLEAR 0xFFFF
-#define L2CAP_SEQ_LIST_TAIL 0x8000
+enum {
+ L2CAP_TX_STATE_XMIT,
+ L2CAP_TX_STATE_WAIT_F,
+};
-#define L2CAP_ERTM_TX_STATE_XMIT 0x01
-#define L2CAP_ERTM_TX_STATE_WAIT_F 0x02
+enum {
+ L2CAP_RX_STATE_RECV,
+ L2CAP_RX_STATE_SREJ_SENT,
+ L2CAP_RX_STATE_MOVE,
+ L2CAP_RX_STATE_WAIT_P,
+ L2CAP_RX_STATE_WAIT_F,
+};
-#define L2CAP_ERTM_RX_STATE_RECV 0x01
-#define L2CAP_ERTM_RX_STATE_SREJ_SENT 0x02
-#define L2CAP_ERTM_RX_STATE_AMP_MOVE 0x03
-#define L2CAP_ERTM_RX_STATE_WAIT_P_FLAG 0x04
-#define L2CAP_ERTM_RX_STATE_WAIT_P_FLAG_RECONFIGURE 0x05
-#define L2CAP_ERTM_RX_STATE_WAIT_F_FLAG 0x06
+enum {
+ L2CAP_TXSEQ_EXPECTED,
+ L2CAP_TXSEQ_EXPECTED_SREJ,
+ L2CAP_TXSEQ_UNEXPECTED,
+ L2CAP_TXSEQ_UNEXPECTED_SREJ,
+ L2CAP_TXSEQ_DUPLICATE,
+ L2CAP_TXSEQ_DUPLICATE_SREJ,
+ L2CAP_TXSEQ_INVALID,
+ L2CAP_TXSEQ_INVALID_IGNORE,
+};
-#define L2CAP_ERTM_TXSEQ_EXPECTED 0x00
-#define L2CAP_ERTM_TXSEQ_EXPECTED_SREJ 0x01
-#define L2CAP_ERTM_TXSEQ_UNEXPECTED 0x02
-#define L2CAP_ERTM_TXSEQ_UNEXPECTED_SREJ 0x03
-#define L2CAP_ERTM_TXSEQ_DUPLICATE 0x04
-#define L2CAP_ERTM_TXSEQ_DUPLICATE_SREJ 0x05
-#define L2CAP_ERTM_TXSEQ_INVALID 0x06
-#define L2CAP_ERTM_TXSEQ_INVALID_IGNORE 0x07
+enum {
+ L2CAP_EV_DATA_REQUEST,
+ L2CAP_EV_LOCAL_BUSY_DETECTED,
+ L2CAP_EV_LOCAL_BUSY_CLEAR,
+ L2CAP_EV_RECV_REQSEQ_AND_FBIT,
+ L2CAP_EV_RECV_FBIT,
+ L2CAP_EV_RETRANS_TO,
+ L2CAP_EV_MONITOR_TO,
+ L2CAP_EV_EXPLICIT_POLL,
+ L2CAP_EV_RECV_IFRAME,
+ L2CAP_EV_RECV_RR,
+ L2CAP_EV_RECV_REJ,
+ L2CAP_EV_RECV_RNR,
+ L2CAP_EV_RECV_SREJ,
+ L2CAP_EV_RECV_FRAME,
+};
-#define L2CAP_ERTM_EVENT_DATA_REQUEST 0x01
-#define L2CAP_ERTM_EVENT_LOCAL_BUSY_DETECTED 0x02
-#define L2CAP_ERTM_EVENT_LOCAL_BUSY_CLEAR 0x03
-#define L2CAP_ERTM_EVENT_RECV_REQSEQ_AND_FBIT 0x04
-#define L2CAP_ERTM_EVENT_RECV_FBIT 0x05
-#define L2CAP_ERTM_EVENT_RETRANS_TIMER_EXPIRES 0x06
-#define L2CAP_ERTM_EVENT_MONITOR_TIMER_EXPIRES 0x07
-#define L2CAP_ERTM_EVENT_EXPLICIT_POLL 0x08
-#define L2CAP_ERTM_EVENT_RECV_IFRAME 0x09
-#define L2CAP_ERTM_EVENT_RECV_RR 0x0a
-#define L2CAP_ERTM_EVENT_RECV_REJ 0x0b
-#define L2CAP_ERTM_EVENT_RECV_RNR 0x0c
-#define L2CAP_ERTM_EVENT_RECV_SREJ 0x0d
-#define L2CAP_ERTM_EVENT_RECV_FRAME 0x0e
+enum {
+ L2CAP_MOVE_ROLE_NONE,
+ L2CAP_MOVE_ROLE_INITIATOR,
+ L2CAP_MOVE_ROLE_RESPONDER,
+};
-#define L2CAP_AMP_MOVE_NONE 0
-#define L2CAP_AMP_MOVE_INITIATOR 1
-#define L2CAP_AMP_MOVE_RESPONDER 2
+enum {
+ L2CAP_MOVE_STABLE,
+ L2CAP_MOVE_WAIT_REQ,
+ L2CAP_MOVE_WAIT_RSP,
+ L2CAP_MOVE_WAIT_RSP_SUCCESS,
+ L2CAP_MOVE_WAIT_CONFIRM,
+ L2CAP_MOVE_WAIT_CONFIRM_RSP,
+ L2CAP_MOVE_WAIT_LOGICAL_COMP,
+ L2CAP_MOVE_WAIT_LOGICAL_CFM,
+ L2CAP_MOVE_WAIT_LOCAL_BUSY,
+ L2CAP_MOVE_WAIT_PREPARE,
+};
-#define L2CAP_AMP_STATE_STABLE 0
-#define L2CAP_AMP_STATE_WAIT_CREATE 1
-#define L2CAP_AMP_STATE_WAIT_CREATE_RSP 2
-#define L2CAP_AMP_STATE_WAIT_MOVE 3
-#define L2CAP_AMP_STATE_WAIT_MOVE_RSP 4
-#define L2CAP_AMP_STATE_WAIT_MOVE_RSP_SUCCESS 5
-#define L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM 6
-#define L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM_RSP 7
-#define L2CAP_AMP_STATE_WAIT_LOGICAL_COMPLETE 8
-#define L2CAP_AMP_STATE_WAIT_LOGICAL_CONFIRM 9
-#define L2CAP_AMP_STATE_WAIT_LOCAL_BUSY 10
-#define L2CAP_AMP_STATE_WAIT_PREPARE 11
-#define L2CAP_AMP_STATE_RESEGMENT 12
+void l2cap_chan_hold(struct l2cap_chan *c);
+void l2cap_chan_put(struct l2cap_chan *c);
-#define L2CAP_ATT_ERROR 0x01
-#define L2CAP_ATT_MTU_REQ 0x02
-#define L2CAP_ATT_MTU_RSP 0x03
-#define L2CAP_ATT_RESPONSE_BIT 0x01
-#define L2CAP_ATT_INDICATE 0x1D
-#define L2CAP_ATT_CONFIRM 0x1E
-#define L2CAP_ATT_NOT_SUPPORTED 0x06
+static inline void l2cap_chan_lock(struct l2cap_chan *chan)
+{
+ mutex_lock(&chan->lock);
+}
-#define __delta_seq(x, y, pi) ((x) >= (y) ? (x) - (y) : \
- (pi)->tx_win_max + 1 - (y) + (x))
-#define __next_seq(x, pi) ((x + 1) & ((pi)->tx_win_max))
+static inline void l2cap_chan_unlock(struct l2cap_chan *chan)
+{
+ mutex_unlock(&chan->lock);
+}
+
+static inline void l2cap_set_timer(struct l2cap_chan *chan,
+ struct delayed_work *work, long timeout)
+{
+ BT_DBG("chan %p state %s timeout %ld", chan,
+ state_to_string(chan->state), timeout);
+
+ /* If delayed work cancelled do not hold(chan)
+ since it is already done with previous set_timer */
+ if (!cancel_delayed_work(work))
+ l2cap_chan_hold(chan);
+
+ schedule_delayed_work(work, timeout);
+}
+
+static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
+ struct delayed_work *work)
+{
+ bool ret;
+
+ /* put(chan) if delayed work cancelled otherwise it
+ is done in delayed work function */
+ ret = cancel_delayed_work(work);
+ if (ret)
+ l2cap_chan_put(chan);
+
+ return ret;
+}
+
+#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
+#define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
+#define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer)
+#define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer)
+#define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \
+ msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO));
+#define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer)
+
+static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2)
+{
+ if (seq1 >= seq2)
+ return seq1 - seq2;
+ else
+ return chan->tx_win_max + 1 - seq2 + seq1;
+}
+
+static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
+{
+ return (seq + 1) % (chan->tx_win_max + 1);
+}
+
+static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan *chan)
+{
+ return NULL;
+}
+
+static inline void l2cap_chan_no_teardown(struct l2cap_chan *chan, int err)
+{
+}
+
+static inline void l2cap_chan_no_ready(struct l2cap_chan *chan)
+{
+}
+
+static inline void l2cap_chan_no_defer(struct l2cap_chan *chan)
+{
+}
extern bool disable_ertm;
-extern const struct proto_ops l2cap_sock_ops;
-extern struct bt_sock_list l2cap_sk_list;
int l2cap_init_sockets(void);
void l2cap_cleanup_sockets(void);
+bool l2cap_is_socket(struct socket *sock);
-u8 l2cap_get_ident(struct l2cap_conn *conn);
-void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data);
-int l2cap_build_conf_req(struct sock *sk, void *data);
+void __l2cap_connect_rsp_defer(struct l2cap_chan *chan);
int __l2cap_wait_ack(struct sock *sk);
-struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len);
-struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len);
-struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg,
- size_t len, u16 sdulen, int reseg);
-int l2cap_segment_sdu(struct sock *sk, struct sk_buff_head* seg_queue,
- struct msghdr *msg, size_t len, int reseg);
-int l2cap_resegment_queue(struct sock *sk, struct sk_buff_head *queue);
-void l2cap_do_send(struct sock *sk, struct sk_buff *skb);
-void l2cap_streaming_send(struct sock *sk);
-int l2cap_ertm_send(struct sock *sk);
-int l2cap_strm_tx(struct sock *sk, struct sk_buff_head *skbs);
-int l2cap_ertm_tx(struct sock *sk, struct bt_l2cap_control *control,
- struct sk_buff_head *skbs, u8 event);
+int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm);
+int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid);
-int l2cap_sock_le_params_valid(struct bt_le_params *le_params);
-void l2cap_sock_set_timer(struct sock *sk, long timeout);
-void l2cap_sock_clear_timer(struct sock *sk);
-void __l2cap_sock_close(struct sock *sk, int reason);
-void l2cap_sock_kill(struct sock *sk);
-void l2cap_sock_init(struct sock *sk, struct sock *parent);
-struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
- int proto, gfp_t prio);
-struct sock *l2cap_find_sock_by_fixed_cid_and_dir(__le16 cid, bdaddr_t *src,
- bdaddr_t *dst, int server);
-void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err);
-void l2cap_chan_del(struct sock *sk, int err);
-int l2cap_do_connect(struct sock *sk);
-int l2cap_data_channel(struct sock *sk, struct sk_buff *skb);
-void l2cap_amp_move_init(struct sock *sk);
-void l2cap_ertm_destruct(struct sock *sk);
-void l2cap_ertm_shutdown(struct sock *sk);
-void l2cap_ertm_recv_done(struct sock *sk);
+struct l2cap_chan *l2cap_chan_create(void);
+void l2cap_chan_close(struct l2cap_chan *chan, int reason);
+int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
+ bdaddr_t *dst, u8 dst_type);
+int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
+ u32 priority);
+void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
+int l2cap_chan_check_security(struct l2cap_chan *chan);
+void l2cap_chan_set_defaults(struct l2cap_chan *chan);
+int l2cap_ertm_init(struct l2cap_chan *chan);
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
+void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
+void l2cap_chan_del(struct l2cap_chan *chan, int err);
+void l2cap_send_conn_req(struct l2cap_chan *chan);
+void l2cap_move_start(struct l2cap_chan *chan);
+void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
+ u8 status);
+void __l2cap_physical_cfm(struct l2cap_chan *chan, int result);
-void l2cap_fixed_channel_config(struct sock *sk, struct l2cap_options *opt);
+void l2cap_conn_get(struct l2cap_conn *conn);
+void l2cap_conn_put(struct l2cap_conn *conn);
-void l2cap_recv_deferred_frame(struct sock *sk, struct sk_buff *skb);
-
-void l2cap_amp_physical_complete(int result, u8 remote_id, u8 local_id,
- struct sock *sk);
-
-void l2cap_amp_logical_complete(int result, struct hci_conn *ampcon,
- struct hci_chan *ampchan, struct sock *sk);
-
-void l2cap_amp_logical_destroyed(struct hci_conn *ampcon);
-
-void l2cap_conn_del(struct hci_conn *hcon, int err, u8 is_process);
+int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user);
+void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user);
#endif /* __L2CAP_H */
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 3bf514f..9944c3e 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -2,6 +2,7 @@
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2010 Nokia Corporation
+ Copyright (C) 2011-2012 Intel Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
@@ -23,399 +24,465 @@
#define MGMT_INDEX_NONE 0xFFFF
+#define MGMT_STATUS_SUCCESS 0x00
+#define MGMT_STATUS_UNKNOWN_COMMAND 0x01
+#define MGMT_STATUS_NOT_CONNECTED 0x02
+#define MGMT_STATUS_FAILED 0x03
+#define MGMT_STATUS_CONNECT_FAILED 0x04
+#define MGMT_STATUS_AUTH_FAILED 0x05
+#define MGMT_STATUS_NOT_PAIRED 0x06
+#define MGMT_STATUS_NO_RESOURCES 0x07
+#define MGMT_STATUS_TIMEOUT 0x08
+#define MGMT_STATUS_ALREADY_CONNECTED 0x09
+#define MGMT_STATUS_BUSY 0x0a
+#define MGMT_STATUS_REJECTED 0x0b
+#define MGMT_STATUS_NOT_SUPPORTED 0x0c
+#define MGMT_STATUS_INVALID_PARAMS 0x0d
+#define MGMT_STATUS_DISCONNECTED 0x0e
+#define MGMT_STATUS_NOT_POWERED 0x0f
+#define MGMT_STATUS_CANCELLED 0x10
+#define MGMT_STATUS_INVALID_INDEX 0x11
+#define MGMT_STATUS_RFKILLED 0x12
+
struct mgmt_hdr {
- __le16 opcode;
- __le16 index;
- __le16 len;
+ __le16 opcode;
+ __le16 index;
+ __le16 len;
} __packed;
+struct mgmt_addr_info {
+ bdaddr_t bdaddr;
+ __u8 type;
+} __packed;
+#define MGMT_ADDR_INFO_SIZE 7
+
#define MGMT_OP_READ_VERSION 0x0001
+#define MGMT_READ_VERSION_SIZE 0
struct mgmt_rp_read_version {
- __u8 version;
- __le16 revision;
+ __u8 version;
+ __le16 revision;
+} __packed;
+
+#define MGMT_OP_READ_COMMANDS 0x0002
+#define MGMT_READ_COMMANDS_SIZE 0
+struct mgmt_rp_read_commands {
+ __le16 num_commands;
+ __le16 num_events;
+ __le16 opcodes[0];
} __packed;
#define MGMT_OP_READ_INDEX_LIST 0x0003
+#define MGMT_READ_INDEX_LIST_SIZE 0
struct mgmt_rp_read_index_list {
- __le16 num_controllers;
- __le16 index[0];
+ __le16 num_controllers;
+ __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_MAX_SHORT_NAME_LENGTH (HCI_MAX_SHORT_NAME_LENGTH + 1)
+
+#define MGMT_SETTING_POWERED 0x00000001
+#define MGMT_SETTING_CONNECTABLE 0x00000002
+#define MGMT_SETTING_FAST_CONNECTABLE 0x00000004
+#define MGMT_SETTING_DISCOVERABLE 0x00000008
+#define MGMT_SETTING_PAIRABLE 0x00000010
+#define MGMT_SETTING_LINK_SECURITY 0x00000020
+#define MGMT_SETTING_SSP 0x00000040
+#define MGMT_SETTING_BREDR 0x00000080
+#define MGMT_SETTING_HS 0x00000100
+#define MGMT_SETTING_LE 0x00000200
#define MGMT_OP_READ_INFO 0x0004
+#define MGMT_READ_INFO_SIZE 0
struct mgmt_rp_read_info {
- __u8 type;
- __u8 powered;
- __u8 connectable;
- __u8 discoverable;
- __u8 pairable;
- __u8 sec_mode;
- bdaddr_t bdaddr;
- __u8 dev_class[3];
- __u8 features[8];
- __u16 manufacturer;
- __u8 hci_ver;
- __u16 hci_rev;
- __u8 name[MGMT_MAX_NAME_LENGTH];
- __u8 le_white_list_size;
+ bdaddr_t bdaddr;
+ __u8 version;
+ __le16 manufacturer;
+ __le32 supported_settings;
+ __le32 current_settings;
+ __u8 dev_class[3];
+ __u8 name[MGMT_MAX_NAME_LENGTH];
+ __u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH];
} __packed;
struct mgmt_mode {
__u8 val;
} __packed;
+#define MGMT_SETTING_SIZE 1
+
#define MGMT_OP_SET_POWERED 0x0005
#define MGMT_OP_SET_DISCOVERABLE 0x0006
+struct mgmt_cp_set_discoverable {
+ __u8 val;
+ __le16 timeout;
+} __packed;
+#define MGMT_SET_DISCOVERABLE_SIZE 3
#define MGMT_OP_SET_CONNECTABLE 0x0007
-#define MGMT_OP_SET_PAIRABLE 0x0008
+#define MGMT_OP_SET_FAST_CONNECTABLE 0x0008
-#define MGMT_OP_ADD_UUID 0x0009
-struct mgmt_cp_add_uuid {
- __u8 uuid[16];
- __u8 svc_hint;
-} __packed;
+#define MGMT_OP_SET_PAIRABLE 0x0009
-#define MGMT_OP_REMOVE_UUID 0x000A
-struct mgmt_cp_remove_uuid {
- __u8 uuid[16];
-} __packed;
+#define MGMT_OP_SET_LINK_SECURITY 0x000A
-#define MGMT_OP_SET_DEV_CLASS 0x000B
+#define MGMT_OP_SET_SSP 0x000B
+
+#define MGMT_OP_SET_HS 0x000C
+
+#define MGMT_OP_SET_LE 0x000D
+#define MGMT_OP_SET_DEV_CLASS 0x000E
struct mgmt_cp_set_dev_class {
- __u8 major;
- __u8 minor;
+ __u8 major;
+ __u8 minor;
} __packed;
-#define MGMT_MAJOR_CLASS_MASK 0x1F
-#define MGMT_MAJOR_CLASS_LIMITED 0x20
+#define MGMT_SET_DEV_CLASS_SIZE 2
-#define MGMT_OP_SET_SERVICE_CACHE 0x000C
-struct mgmt_cp_set_service_cache {
- __u8 enable;
+#define MGMT_OP_SET_LOCAL_NAME 0x000F
+struct mgmt_cp_set_local_name {
+ __u8 name[MGMT_MAX_NAME_LENGTH];
+ __u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH];
+} __packed;
+#define MGMT_SET_LOCAL_NAME_SIZE 260
+
+#define MGMT_OP_ADD_UUID 0x0010
+struct mgmt_cp_add_uuid {
+ __u8 uuid[16];
+ __u8 svc_hint;
+} __packed;
+#define MGMT_ADD_UUID_SIZE 17
+
+#define MGMT_OP_REMOVE_UUID 0x0011
+struct mgmt_cp_remove_uuid {
+ __u8 uuid[16];
+} __packed;
+#define MGMT_REMOVE_UUID_SIZE 16
+
+struct mgmt_link_key_info {
+ struct mgmt_addr_info addr;
+ __u8 type;
+ __u8 val[16];
+ __u8 pin_len;
} __packed;
-struct mgmt_key_info {
- bdaddr_t bdaddr;
- u8 addr_type;
- u8 key_type;
- u8 val[16];
- u8 pin_len;
- u8 auth;
- u8 dlen;
- u8 data[10];
+#define MGMT_OP_LOAD_LINK_KEYS 0x0012
+struct mgmt_cp_load_link_keys {
+ __u8 debug_keys;
+ __le16 key_count;
+ struct mgmt_link_key_info keys[0];
+} __packed;
+#define MGMT_LOAD_LINK_KEYS_SIZE 3
+
+struct mgmt_ltk_info {
+ struct mgmt_addr_info addr;
+ __u8 authenticated;
+ __u8 master;
+ __u8 enc_size;
+ __le16 ediv;
+ __u8 rand[8];
+ __u8 val[16];
} __packed;
-#define MGMT_OP_LOAD_KEYS 0x000D
-struct mgmt_cp_load_keys {
- __u8 debug_keys;
- __le16 key_count;
- struct mgmt_key_info keys[0];
+#define MGMT_OP_LOAD_LONG_TERM_KEYS 0x0013
+struct mgmt_cp_load_long_term_keys {
+ __le16 key_count;
+ struct mgmt_ltk_info keys[0];
} __packed;
+#define MGMT_LOAD_LONG_TERM_KEYS_SIZE 2
-#define MGMT_OP_REMOVE_KEY 0x000E
-struct mgmt_cp_remove_key {
- bdaddr_t bdaddr;
- __u8 disconnect;
-} __packed;
-
-#define MGMT_OP_DISCONNECT 0x000F
+#define MGMT_OP_DISCONNECT 0x0014
struct mgmt_cp_disconnect {
- bdaddr_t bdaddr;
+ struct mgmt_addr_info addr;
} __packed;
+#define MGMT_DISCONNECT_SIZE MGMT_ADDR_INFO_SIZE
struct mgmt_rp_disconnect {
- bdaddr_t bdaddr;
+ struct mgmt_addr_info addr;
} __packed;
-#define MGMT_OP_GET_CONNECTIONS 0x0010
+#define MGMT_OP_GET_CONNECTIONS 0x0015
+#define MGMT_GET_CONNECTIONS_SIZE 0
struct mgmt_rp_get_connections {
__le16 conn_count;
- bdaddr_t conn[0];
+ struct mgmt_addr_info addr[0];
} __packed;
-#define MGMT_OP_PIN_CODE_REPLY 0x0011
+#define MGMT_OP_PIN_CODE_REPLY 0x0016
struct mgmt_cp_pin_code_reply {
- bdaddr_t bdaddr;
- __u8 pin_len;
- __u8 pin_code[16];
+ struct mgmt_addr_info addr;
+ __u8 pin_len;
+ __u8 pin_code[16];
} __packed;
+#define MGMT_PIN_CODE_REPLY_SIZE (MGMT_ADDR_INFO_SIZE + 17)
struct mgmt_rp_pin_code_reply {
- bdaddr_t bdaddr;
- uint8_t status;
+ struct mgmt_addr_info addr;
} __packed;
-#define MGMT_OP_PIN_CODE_NEG_REPLY 0x0012
+#define MGMT_OP_PIN_CODE_NEG_REPLY 0x0017
struct mgmt_cp_pin_code_neg_reply {
- bdaddr_t bdaddr;
+ struct mgmt_addr_info addr;
} __packed;
+#define MGMT_PIN_CODE_NEG_REPLY_SIZE MGMT_ADDR_INFO_SIZE
-#define MGMT_OP_SET_IO_CAPABILITY 0x0013
+#define MGMT_OP_SET_IO_CAPABILITY 0x0018
struct mgmt_cp_set_io_capability {
- __u8 io_capability;
+ __u8 io_capability;
} __packed;
+#define MGMT_SET_IO_CAPABILITY_SIZE 1
-#define MGMT_OP_PAIR_DEVICE 0x0014
+#define MGMT_OP_PAIR_DEVICE 0x0019
struct mgmt_cp_pair_device {
- bdaddr_t bdaddr;
- __u8 io_cap;
+ struct mgmt_addr_info addr;
+ __u8 io_cap;
} __packed;
+#define MGMT_PAIR_DEVICE_SIZE (MGMT_ADDR_INFO_SIZE + 1)
struct mgmt_rp_pair_device {
- bdaddr_t bdaddr;
- __u8 status;
+ struct mgmt_addr_info addr;
} __packed;
-#define MGMT_OP_USER_CONFIRM_REPLY 0x0015
+#define MGMT_OP_CANCEL_PAIR_DEVICE 0x001A
+#define MGMT_CANCEL_PAIR_DEVICE_SIZE MGMT_ADDR_INFO_SIZE
+
+#define MGMT_OP_UNPAIR_DEVICE 0x001B
+struct mgmt_cp_unpair_device {
+ struct mgmt_addr_info addr;
+ __u8 disconnect;
+} __packed;
+#define MGMT_UNPAIR_DEVICE_SIZE (MGMT_ADDR_INFO_SIZE + 1)
+struct mgmt_rp_unpair_device {
+ struct mgmt_addr_info addr;
+};
+
+#define MGMT_OP_USER_CONFIRM_REPLY 0x001C
struct mgmt_cp_user_confirm_reply {
- bdaddr_t bdaddr;
+ struct mgmt_addr_info addr;
} __packed;
+#define MGMT_USER_CONFIRM_REPLY_SIZE MGMT_ADDR_INFO_SIZE
struct mgmt_rp_user_confirm_reply {
- bdaddr_t bdaddr;
- __u8 status;
+ struct mgmt_addr_info addr;
} __packed;
-#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];
+#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001D
+struct mgmt_cp_user_confirm_neg_reply {
+ struct mgmt_addr_info addr;
} __packed;
+#define MGMT_USER_CONFIRM_NEG_REPLY_SIZE MGMT_ADDR_INFO_SIZE
-#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_OP_START_DISCOVERY 0x001B
-
-#define MGMT_OP_STOP_DISCOVERY 0x001C
-
-#define MGMT_OP_USER_PASSKEY_REPLY 0x001D
+#define MGMT_OP_USER_PASSKEY_REPLY 0x001E
struct mgmt_cp_user_passkey_reply {
- bdaddr_t bdaddr;
- __le32 passkey;
+ struct mgmt_addr_info addr;
+ __le32 passkey;
+} __packed;
+#define MGMT_USER_PASSKEY_REPLY_SIZE (MGMT_ADDR_INFO_SIZE + 4)
+struct mgmt_rp_user_passkey_reply {
+ struct mgmt_addr_info addr;
} __packed;
-#define MGMT_OP_RESOLVE_NAME 0x001E
-struct mgmt_cp_resolve_name {
- bdaddr_t bdaddr;
+#define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001F
+struct mgmt_cp_user_passkey_neg_reply {
+ struct mgmt_addr_info addr;
+} __packed;
+#define MGMT_USER_PASSKEY_NEG_REPLY_SIZE MGMT_ADDR_INFO_SIZE
+
+#define MGMT_OP_READ_LOCAL_OOB_DATA 0x0020
+#define MGMT_READ_LOCAL_OOB_DATA_SIZE 0
+struct mgmt_rp_read_local_oob_data {
+ __u8 hash[16];
+ __u8 randomizer[16];
} __packed;
-#define MGMT_OP_SET_LIMIT_DISCOVERABLE 0x001F
+#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0021
+struct mgmt_cp_add_remote_oob_data {
+ struct mgmt_addr_info addr;
+ __u8 hash[16];
+ __u8 randomizer[16];
+} __packed;
+#define MGMT_ADD_REMOTE_OOB_DATA_SIZE (MGMT_ADDR_INFO_SIZE + 32)
-#define MGMT_OP_SET_CONNECTION_PARAMS 0x0020
-struct mgmt_cp_set_connection_params {
- bdaddr_t bdaddr;
- __le16 interval_min;
- __le16 interval_max;
- __le16 slave_latency;
- __le16 timeout_multiplier;
+#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0022
+struct mgmt_cp_remove_remote_oob_data {
+ struct mgmt_addr_info addr;
+} __packed;
+#define MGMT_REMOVE_REMOTE_OOB_DATA_SIZE MGMT_ADDR_INFO_SIZE
+
+#define MGMT_OP_START_DISCOVERY 0x0023
+struct mgmt_cp_start_discovery {
+ __u8 type;
+} __packed;
+#define MGMT_START_DISCOVERY_SIZE 1
+
+#define MGMT_OP_STOP_DISCOVERY 0x0024
+struct mgmt_cp_stop_discovery {
+ __u8 type;
+} __packed;
+#define MGMT_STOP_DISCOVERY_SIZE 1
+
+#define MGMT_OP_CONFIRM_NAME 0x0025
+struct mgmt_cp_confirm_name {
+ struct mgmt_addr_info addr;
+ __u8 name_known;
+} __packed;
+#define MGMT_CONFIRM_NAME_SIZE (MGMT_ADDR_INFO_SIZE + 1)
+struct mgmt_rp_confirm_name {
+ struct mgmt_addr_info addr;
} __packed;
-#define MGMT_OP_ENCRYPT_LINK 0x0021
-struct mgmt_cp_encrypt_link {
- bdaddr_t bdaddr;
- __u8 enable;
+#define MGMT_OP_BLOCK_DEVICE 0x0026
+struct mgmt_cp_block_device {
+ struct mgmt_addr_info addr;
} __packed;
+#define MGMT_BLOCK_DEVICE_SIZE MGMT_ADDR_INFO_SIZE
-#define MGMT_OP_SET_RSSI_REPORTER 0x0022
-struct mgmt_cp_set_rssi_reporter {
- bdaddr_t bdaddr;
- __s8 rssi_threshold;
- __le16 interval;
- __u8 updateOnThreshExceed;
+#define MGMT_OP_UNBLOCK_DEVICE 0x0027
+struct mgmt_cp_unblock_device {
+ struct mgmt_addr_info addr;
} __packed;
+#define MGMT_UNBLOCK_DEVICE_SIZE MGMT_ADDR_INFO_SIZE
-#define MGMT_OP_UNSET_RSSI_REPORTER 0x0023
-struct mgmt_cp_unset_rssi_reporter {
- bdaddr_t bdaddr;
+#define MGMT_OP_SET_DEVICE_ID 0x0028
+struct mgmt_cp_set_device_id {
+ __le16 source;
+ __le16 vendor;
+ __le16 product;
+ __le16 version;
} __packed;
-
-#define MGMT_OP_CANCEL_RESOLVE_NAME 0x0024
-struct mgmt_cp_cancel_resolve_name {
- bdaddr_t bdaddr;
-} __packed;
-
-#define MGMT_OP_LE_READ_WHITE_LIST_SIZE 0xE000
-
-#define MGMT_OP_LE_CLEAR_WHITE_LIST 0xE001
-
-#define MGMT_OP_LE_ADD_DEV_WHITE_LIST 0xE002
-struct mgmt_cp_le_add_dev_white_list {
- __u8 addr_type;
- bdaddr_t bdaddr;
-} __packed;
-
-#define MGMT_OP_LE_REMOVE_DEV_WHITE_LIST 0xE003
-struct mgmt_cp_le_remove_dev_white_list {
- __u8 addr_type;
- bdaddr_t bdaddr;
-} __packed;
-
-#define MGMT_OP_LE_CREATE_CONN_WHITE_LIST 0xE004
-
-#define MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST 0xE005
-
-#define MGMT_OP_LE_CANCEL_CREATE_CONN 0xE006
-struct mgmt_cp_le_cancel_create_conn {
- bdaddr_t bdaddr;
-} __packed;
+#define MGMT_SET_DEVICE_ID_SIZE 8
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
- __le16 opcode;
- __u8 data[0];
+ __le16 opcode;
+ __u8 status;
+ __u8 data[0];
} __packed;
#define MGMT_EV_CMD_STATUS 0x0002
struct mgmt_ev_cmd_status {
- __u8 status;
- __le16 opcode;
+ __le16 opcode;
+ __u8 status;
} __packed;
#define MGMT_EV_CONTROLLER_ERROR 0x0003
struct mgmt_ev_controller_error {
- __u8 error_code;
+ __u8 error_code;
} __packed;
#define MGMT_EV_INDEX_ADDED 0x0004
#define MGMT_EV_INDEX_REMOVED 0x0005
-#define MGMT_EV_POWERED 0x0006
+#define MGMT_EV_NEW_SETTINGS 0x0006
-#define MGMT_EV_DISCOVERABLE 0x0007
+#define MGMT_EV_CLASS_OF_DEV_CHANGED 0x0007
+struct mgmt_ev_class_of_dev_changed {
+ __u8 dev_class[3];
+};
-#define MGMT_EV_CONNECTABLE 0x0008
-
-#define MGMT_EV_PAIRABLE 0x0009
-
-#define MGMT_EV_NEW_KEY 0x000A
-struct mgmt_ev_new_key {
- __u8 store_hint;
- struct mgmt_key_info key;
+#define MGMT_EV_LOCAL_NAME_CHANGED 0x0008
+struct mgmt_ev_local_name_changed {
+ __u8 name[MGMT_MAX_NAME_LENGTH];
+ __u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH];
} __packed;
-#define MGMT_EV_CONNECTED 0x000B
-struct mgmt_ev_connected {
- bdaddr_t bdaddr;
- __u8 le;
+#define MGMT_EV_NEW_LINK_KEY 0x0009
+struct mgmt_ev_new_link_key {
+ __u8 store_hint;
+ struct mgmt_link_key_info key;
} __packed;
-#define MGMT_EV_DISCONNECTED 0x000C
-struct mgmt_ev_disconnected {
- bdaddr_t bdaddr;
- __u8 reason;
+#define MGMT_EV_NEW_LONG_TERM_KEY 0x000A
+struct mgmt_ev_new_long_term_key {
+ __u8 store_hint;
+ struct mgmt_ltk_info key;
+} __packed;
+
+#define MGMT_EV_DEVICE_CONNECTED 0x000B
+struct mgmt_ev_device_connected {
+ struct mgmt_addr_info addr;
+ __le32 flags;
+ __le16 eir_len;
+ __u8 eir[0];
+} __packed;
+
+#define MGMT_DEV_DISCONN_UNKNOWN 0x00
+#define MGMT_DEV_DISCONN_TIMEOUT 0x01
+#define MGMT_DEV_DISCONN_LOCAL_HOST 0x02
+#define MGMT_DEV_DISCONN_REMOTE 0x03
+
+#define MGMT_EV_DEVICE_DISCONNECTED 0x000C
+struct mgmt_ev_device_disconnected {
+ struct mgmt_addr_info addr;
+ __u8 reason;
} __packed;
#define MGMT_EV_CONNECT_FAILED 0x000D
struct mgmt_ev_connect_failed {
- bdaddr_t bdaddr;
- __u8 status;
+ struct mgmt_addr_info addr;
+ __u8 status;
} __packed;
#define MGMT_EV_PIN_CODE_REQUEST 0x000E
struct mgmt_ev_pin_code_request {
- bdaddr_t bdaddr;
- __u8 secure;
+ struct mgmt_addr_info addr;
+ __u8 secure;
} __packed;
#define MGMT_EV_USER_CONFIRM_REQUEST 0x000F
struct mgmt_ev_user_confirm_request {
- bdaddr_t bdaddr;
- __u8 auto_confirm;
- __u8 event;
- __le32 value;
+ struct mgmt_addr_info addr;
+ __u8 confirm_hint;
+ __le32 value;
} __packed;
-#define MGMT_EV_AUTH_FAILED 0x0010
+#define MGMT_EV_USER_PASSKEY_REQUEST 0x0010
+struct mgmt_ev_user_passkey_request {
+ struct mgmt_addr_info addr;
+} __packed;
+
+#define MGMT_EV_AUTH_FAILED 0x0011
struct mgmt_ev_auth_failed {
- bdaddr_t bdaddr;
- __u8 status;
+ struct mgmt_addr_info addr;
+ __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_DEV_FOUND_CONFIRM_NAME 0x01
+#define MGMT_DEV_FOUND_LEGACY_PAIRING 0x02
#define MGMT_EV_DEVICE_FOUND 0x0012
struct mgmt_ev_device_found {
- bdaddr_t bdaddr;
- __u8 dev_class[3];
- __s8 rssi;
- __u8 le;
- __u8 type;
- __u8 eir[HCI_MAX_EIR_LENGTH];
+ struct mgmt_addr_info addr;
+ __s8 rssi;
+ __le32 flags;
+ __le16 eir_len;
+ __u8 eir[0];
} __packed;
-#define MGMT_EV_REMOTE_NAME 0x0013
-struct mgmt_ev_remote_name {
- bdaddr_t bdaddr;
- __u8 status;
- __u8 name[MGMT_MAX_NAME_LENGTH];
+#define MGMT_EV_DISCOVERING 0x0013
+struct mgmt_ev_discovering {
+ __u8 type;
+ __u8 discovering;
} __packed;
-#define MGMT_EV_DISCOVERING 0x0014
-
-#define MGMT_EV_USER_PASSKEY_REQUEST 0x0015
-struct mgmt_ev_user_passkey_request {
- bdaddr_t bdaddr;
+#define MGMT_EV_DEVICE_BLOCKED 0x0014
+struct mgmt_ev_device_blocked {
+ struct mgmt_addr_info addr;
} __packed;
-#define MGMT_EV_ENCRYPT_CHANGE 0x0016
-struct mgmt_ev_encrypt_change {
- bdaddr_t bdaddr;
- __u8 status;
+#define MGMT_EV_DEVICE_UNBLOCKED 0x0015
+struct mgmt_ev_device_unblocked {
+ struct mgmt_addr_info addr;
} __packed;
-
-#define MGMT_EV_REMOTE_CLASS 0x0017
-struct mgmt_ev_remote_class {
- bdaddr_t bdaddr;
- __u8 dev_class[3];
+#define MGMT_EV_DEVICE_UNPAIRED 0x0016
+struct mgmt_ev_device_unpaired {
+ struct mgmt_addr_info addr;
} __packed;
-#define MGMT_EV_REMOTE_VERSION 0x0018
-struct mgmt_ev_remote_version {
- bdaddr_t bdaddr;
- __u8 lmp_ver;
- __u16 manufacturer;
- __u16 lmp_subver;
-} __packed;
-
-#define MGMT_EV_REMOTE_FEATURES 0x0019
-struct mgmt_ev_remote_features {
- bdaddr_t bdaddr;
- uint8_t features[8];
-} __packed;
-
-#define MGMT_EV_RSSI_UPDATE 0x0020
-struct mgmt_ev_rssi_update {
- bdaddr_t bdaddr;
- __s8 rssi;
-} __packed;
-
-#define MGMT_EV_LE_CONN_PARAMS 0xF000
-struct mgmt_ev_le_conn_params {
- bdaddr_t bdaddr;
- __u16 interval;
- __u16 latency;
- __u16 timeout;
+#define MGMT_EV_PASSKEY_NOTIFY 0x0017
+struct mgmt_ev_passkey_notify {
+ struct mgmt_addr_info addr;
+ __le32 passkey;
+ __u8 entered;
} __packed;
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
index 6eac4a7..7afd419 100644
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -158,7 +158,6 @@
struct timer_list timer;
unsigned long state;
unsigned long flags;
- atomic_t refcnt;
int initiator;
/* Default DLC parameters */
@@ -211,6 +210,7 @@
#define RFCOMM_AUTH_ACCEPT 6
#define RFCOMM_AUTH_REJECT 7
#define RFCOMM_DEFER_SETUP 8
+#define RFCOMM_ENC_DROP 9
/* Scheduling flags and events */
#define RFCOMM_SCHED_WAKEUP 31
@@ -234,7 +234,8 @@
/* ---- RFCOMM DLCs (channels) ---- */
struct rfcomm_dlc *rfcomm_dlc_alloc(gfp_t prio);
void rfcomm_dlc_free(struct rfcomm_dlc *d);
-int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel);
+int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
+ u8 channel);
int rfcomm_dlc_close(struct rfcomm_dlc *d, int reason);
int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb);
int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig);
@@ -271,12 +272,8 @@
}
/* ---- RFCOMM sessions ---- */
-void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst);
-
-static inline void rfcomm_session_hold(struct rfcomm_session *s)
-{
- atomic_inc(&s->refcnt);
-}
+void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src,
+ bdaddr_t *dst);
/* ---- RFCOMM sockets ---- */
struct sockaddr_rc {
@@ -312,7 +309,8 @@
int rfcomm_init_sockets(void);
void rfcomm_cleanup_sockets(void);
-int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d);
+int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel,
+ struct rfcomm_dlc **d);
/* ---- RFCOMM TTY ---- */
#define RFCOMM_MAX_DEV 256
diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h
index 8c85c98..6d1857a 100644
--- a/include/net/bluetooth/sco.h
+++ b/include/net/bluetooth/sco.h
@@ -1,7 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated
- Copyright (c) 2011, The Linux Foundation. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -31,7 +30,7 @@
#define SCO_DEFAULT_FLUSH_TO 0xFFFF
#define SCO_CONN_TIMEOUT (HZ * 40)
-#define SCO_DISCONN_TIMEOUT (HZ * 20)
+#define SCO_DISCONN_TIMEOUT (HZ * 2)
#define SCO_CONN_IDLE_TIMEOUT (HZ * 60)
/* SCO socket address */
@@ -39,7 +38,6 @@
sa_family_t sco_family;
bdaddr_t sco_bdaddr;
__u16 sco_pkt_type;
- __s8 is_wbs;
};
/* SCO socket options */
diff --git a/include/net/bluetooth/smp.h b/include/net/bluetooth/smp.h
index f0f2842..f8ba07f 100644
--- a/include/net/bluetooth/smp.h
+++ b/include/net/bluetooth/smp.h
@@ -55,13 +55,6 @@
#define SMP_AUTH_BONDING 0x01
#define SMP_AUTH_MITM 0x04
-#define SMP_JUST_WORKS 0x00
-#define SMP_JUST_CFM 0x01
-#define SMP_REQ_PASSKEY 0x02
-#define SMP_CFM_PASSKEY 0x03
-#define SMP_REQ_OOB 0x04
-#define SMP_OVERLAP 0xFF
-
#define SMP_CMD_PAIRING_CONFIRM 0x03
struct smp_cmd_pairing_confirm {
__u8 confirm_val[16];
@@ -84,7 +77,7 @@
#define SMP_CMD_MASTER_IDENT 0x07
struct smp_cmd_master_ident {
- __u16 ediv;
+ __le16 ediv;
__u8 rand[8];
} __packed;
@@ -115,18 +108,39 @@
#define SMP_CONFIRM_FAILED 0x04
#define SMP_PAIRING_NOTSUPP 0x05
#define SMP_ENC_KEY_SIZE 0x06
-#define SMP_CMD_NOTSUPP 0x07
-#define SMP_UNSPECIFIED 0x08
+#define SMP_CMD_NOTSUPP 0x07
+#define SMP_UNSPECIFIED 0x08
#define SMP_REPEATED_ATTEMPTS 0x09
#define SMP_MIN_ENC_KEY_SIZE 7
#define SMP_MAX_ENC_KEY_SIZE 16
+#define SMP_FLAG_TK_VALID 1
+#define SMP_FLAG_CFM_PENDING 2
+#define SMP_FLAG_MITM_AUTH 3
+
+struct smp_chan {
+ struct l2cap_conn *conn;
+ u8 preq[7]; /* SMP Pairing Request */
+ u8 prsp[7]; /* SMP Pairing Response */
+ u8 prnd[16]; /* SMP Pairing Random (local) */
+ u8 rrnd[16]; /* SMP Pairing Random (remote) */
+ u8 pcnf[16]; /* SMP Pairing Confirm */
+ u8 tk[16]; /* SMP Temporary Key */
+ u8 enc_key_size;
+ unsigned long smp_flags;
+ struct crypto_blkcipher *tfm;
+ struct work_struct confirm;
+ struct work_struct random;
+
+};
+
/* SMP Commands */
-int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level);
+int smp_conn_security(struct hci_conn *hcon, __u8 sec_level);
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
-int smp_link_encrypt_cmplt(struct l2cap_conn *conn, __u8 status, __u8 encrypt);
-void smp_conn_security_fail(struct l2cap_conn *conn, __u8 code, __u8 reason);
-void smp_timeout(unsigned long l2cap_conn);
+int smp_distribute_keys(struct l2cap_conn *conn, __u8 force);
+int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
+
+void smp_chan_destroy(struct l2cap_conn *conn);
#endif /* __SMP_H */
diff --git a/include/net/sock.h b/include/net/sock.h
index f673ba5..8e986f0 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -624,6 +624,7 @@
* Will use last 4 bytes of packet sent from
* user-space instead.
*/
+ SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */
};
static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)