Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller: "Here is my initial pull request for the networking subsystem during this merge window: 1) Support for ESN in AH (RFC 4302) from Fan Du. 2) Add full kernel doc for ethtool command structures, from Ben Hutchings. 3) Add BCM7xxx PHY driver, from Florian Fainelli. 4) Export computed TCP rate information in netlink socket dumps, from Eric Dumazet. 5) Allow IPSEC SA to be dumped partially using a filter, from Nicolas Dichtel. 6) Convert many drivers to pci_enable_msix_range(), from Alexander Gordeev. 7) Record SKB timestamps more efficiently, from Eric Dumazet. 8) Switch to microsecond resolution for TCP round trip times, also from Eric Dumazet. 9) Clean up and fix 6lowpan fragmentation handling by making use of the existing inet_frag api for it's implementation. 10) Add TX grant mapping to xen-netback driver, from Zoltan Kiss. 11) Auto size SKB lengths when composing netlink messages based upon past message sizes used, from Eric Dumazet. 12) qdisc dumps can take a long time, add a cond_resched(), From Eric Dumazet. 13) Sanitize netpoll core and drivers wrt. SKB handling semantics. Get rid of never-used-in-tree netpoll RX handling. From Eric W Biederman. 14) Support inter-address-family and namespace changing in VTI tunnel driver(s). From Steffen Klassert. 15) Add Altera TSE driver, from Vince Bridgers. 16) Optimizing csum_replace2() so that it doesn't adjust the checksum by checksumming the entire header, from Eric Dumazet. 17) Expand BPF internal implementation for faster interpreting, more direct translations into JIT'd code, and much cleaner uses of BPF filtering in non-socket ocntexts. From Daniel Borkmann and Alexei Starovoitov" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1976 commits) netpoll: Use skb_irq_freeable to make zap_completion_queue safe. net: Add a test to see if a skb is freeable in irq context qlcnic: Fix build failure due to undefined reference to `vxlan_get_rx_port' net: ptp: move PTP classifier in its own file net: sxgbe: make "core_ops" static net: sxgbe: fix logical vs bitwise operation net: sxgbe: sxgbe_mdio_register() frees the bus Call efx_set_channels() before efx->type->dimension_resources() xen-netback: disable rogue vif in kthread context net/mlx4: Set proper build dependancy with vxlan be2net: fix build dependency on VxLAN mac802154: make csma/cca parameters per-wpan mac802154: allow only one WPAN to be up at any given time net: filter: minor: fix kdoc in __sk_run_filter netlink: don't compare the nul-termination in nla_strcmp can: c_can: Avoid led toggling for every packet. can: c_can: Simplify TX interrupt cleanup can: c_can: Store dlc private can: c_can: Reduce register access can: c_can: Make the code readable ...
This commit is contained in:
@@ -27,7 +27,7 @@
|
||||
|
||||
#include "6lowpan.h"
|
||||
|
||||
#include "../ieee802154/6lowpan.h" /* for the compression support */
|
||||
#include <net/6lowpan.h> /* for the compression support */
|
||||
|
||||
#define IFACE_NAME_TEMPLATE "bt%d"
|
||||
#define EUI64_ADDR_LEN 8
|
||||
|
@@ -14,13 +14,34 @@
|
||||
#ifndef __6LOWPAN_H
|
||||
#define __6LOWPAN_H
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/bluetooth/l2cap.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_6LOWPAN)
|
||||
int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb);
|
||||
int bt_6lowpan_add_conn(struct l2cap_conn *conn);
|
||||
int bt_6lowpan_del_conn(struct l2cap_conn *conn);
|
||||
int bt_6lowpan_init(void);
|
||||
void bt_6lowpan_cleanup(void);
|
||||
#else
|
||||
static int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static int bt_6lowpan_add_conn(struct l2cap_conn *conn)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
int bt_6lowpan_del_conn(struct l2cap_conn *conn)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static int bt_6lowpan_init(void)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static void bt_6lowpan_cleanup(void) { }
|
||||
#endif
|
||||
|
||||
#endif /* __6LOWPAN_H */
|
||||
|
@@ -6,13 +6,13 @@ menuconfig BT
|
||||
tristate "Bluetooth subsystem support"
|
||||
depends on NET && !S390
|
||||
depends on RFKILL || !RFKILL
|
||||
select 6LOWPAN_IPHC if BT_6LOWPAN
|
||||
select CRC16
|
||||
select CRYPTO
|
||||
select CRYPTO_BLKCIPHER
|
||||
select CRYPTO_AES
|
||||
select CRYPTO_ECB
|
||||
select CRYPTO_SHA256
|
||||
select 6LOWPAN_IPHC
|
||||
help
|
||||
Bluetooth is low-cost, low-power, short-range wireless technology.
|
||||
It was designed as a replacement for cables and other short-range
|
||||
@@ -40,6 +40,12 @@ menuconfig BT
|
||||
to Bluetooth kernel modules are provided in the BlueZ packages. For
|
||||
more information, see <http://www.bluez.org/>.
|
||||
|
||||
config BT_6LOWPAN
|
||||
bool "Bluetooth 6LoWPAN support"
|
||||
depends on BT && IPV6
|
||||
help
|
||||
IPv6 compression over Bluetooth.
|
||||
|
||||
source "net/bluetooth/rfcomm/Kconfig"
|
||||
|
||||
source "net/bluetooth/bnep/Kconfig"
|
||||
|
@@ -10,6 +10,7 @@ obj-$(CONFIG_BT_HIDP) += hidp/
|
||||
|
||||
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
|
||||
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
|
||||
a2mp.o amp.o 6lowpan.o
|
||||
a2mp.o amp.o
|
||||
bluetooth-$(CONFIG_BT_6LOWPAN) += 6lowpan.o
|
||||
|
||||
subdir-ccflags-y += -D__CHECK_ENDIAN__
|
||||
|
@@ -162,7 +162,7 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rsp->mtu = __constant_cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
|
||||
rsp->mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
|
||||
rsp->ext_feat = 0;
|
||||
|
||||
__a2mp_add_cl(mgr, rsp->cl);
|
||||
@@ -235,7 +235,7 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
|
||||
BT_DBG("chan %p state %s", chan,
|
||||
state_to_string(chan->state));
|
||||
|
||||
if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP)
|
||||
if (chan->scid == L2CAP_CID_A2MP)
|
||||
continue;
|
||||
|
||||
l2cap_chan_lock(chan);
|
||||
@@ -649,7 +649,7 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
if (err) {
|
||||
struct a2mp_cmd_rej rej;
|
||||
|
||||
rej.reason = __constant_cpu_to_le16(0);
|
||||
rej.reason = cpu_to_le16(0);
|
||||
hdr = (void *) skb->data;
|
||||
|
||||
BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err);
|
||||
@@ -695,7 +695,13 @@ static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state,
|
||||
static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
|
||||
unsigned long len, int nb)
|
||||
{
|
||||
return bt_skb_alloc(len, GFP_KERNEL);
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = bt_skb_alloc(len, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
static struct l2cap_ops a2mp_chan_ops = {
|
||||
@@ -726,7 +732,11 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked)
|
||||
|
||||
BT_DBG("chan %p", chan);
|
||||
|
||||
chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP;
|
||||
chan->chan_type = L2CAP_CHAN_FIXED;
|
||||
chan->scid = L2CAP_CID_A2MP;
|
||||
chan->dcid = L2CAP_CID_A2MP;
|
||||
chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
|
||||
chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
|
||||
chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
|
||||
|
||||
chan->ops = &a2mp_chan_ops;
|
||||
|
@@ -31,7 +31,7 @@
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
#define VERSION "2.18"
|
||||
#define VERSION "2.19"
|
||||
|
||||
/* Bluetooth sockets */
|
||||
#define BT_MAX_PROTO 8
|
||||
|
@@ -82,7 +82,7 @@ static void hci_acl_create_connection(struct hci_conn *conn)
|
||||
cp.pscan_rep_mode = ie->data.pscan_rep_mode;
|
||||
cp.pscan_mode = ie->data.pscan_mode;
|
||||
cp.clock_offset = ie->data.clock_offset |
|
||||
__constant_cpu_to_le16(0x8000);
|
||||
cpu_to_le16(0x8000);
|
||||
}
|
||||
|
||||
memcpy(conn->dev_class, ie->data.dev_class, 3);
|
||||
@@ -182,8 +182,8 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
|
||||
|
||||
cp.handle = cpu_to_le16(handle);
|
||||
|
||||
cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
||||
cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
||||
cp.tx_bandwidth = cpu_to_le32(0x00001f40);
|
||||
cp.rx_bandwidth = cpu_to_le32(0x00001f40);
|
||||
cp.voice_setting = cpu_to_le16(conn->setting);
|
||||
|
||||
switch (conn->setting & SCO_AIRMODE_MASK) {
|
||||
@@ -225,13 +225,13 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
|
||||
cp.conn_interval_max = cpu_to_le16(max);
|
||||
cp.conn_latency = cpu_to_le16(latency);
|
||||
cp.supervision_timeout = cpu_to_le16(to_multiplier);
|
||||
cp.min_ce_len = __constant_cpu_to_le16(0x0001);
|
||||
cp.max_ce_len = __constant_cpu_to_le16(0x0001);
|
||||
cp.min_ce_len = cpu_to_le16(0x0000);
|
||||
cp.max_ce_len = cpu_to_le16(0x0000);
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
|
||||
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand,
|
||||
__u8 ltk[16])
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
@@ -242,9 +242,9 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
memcpy(cp.ltk, ltk, sizeof(cp.ltk));
|
||||
cp.rand = rand;
|
||||
cp.ediv = ediv;
|
||||
memcpy(cp.rand, rand, sizeof(cp.rand));
|
||||
memcpy(cp.ltk, ltk, sizeof(cp.ltk));
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
|
||||
}
|
||||
@@ -337,9 +337,9 @@ static void hci_conn_idle(struct work_struct *work)
|
||||
if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) {
|
||||
struct hci_cp_sniff_subrate cp;
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
cp.max_latency = __constant_cpu_to_le16(0);
|
||||
cp.min_remote_timeout = __constant_cpu_to_le16(0);
|
||||
cp.min_local_timeout = __constant_cpu_to_le16(0);
|
||||
cp.max_latency = cpu_to_le16(0);
|
||||
cp.min_remote_timeout = cpu_to_le16(0);
|
||||
cp.min_local_timeout = cpu_to_le16(0);
|
||||
hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
@@ -348,8 +348,8 @@ static void hci_conn_idle(struct work_struct *work)
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
|
||||
cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
|
||||
cp.attempt = __constant_cpu_to_le16(4);
|
||||
cp.timeout = __constant_cpu_to_le16(1);
|
||||
cp.attempt = cpu_to_le16(4);
|
||||
cp.timeout = cpu_to_le16(1);
|
||||
hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
|
||||
}
|
||||
}
|
||||
@@ -363,6 +363,16 @@ static void hci_conn_auto_accept(struct work_struct *work)
|
||||
&conn->dst);
|
||||
}
|
||||
|
||||
static void le_conn_timeout(struct work_struct *work)
|
||||
{
|
||||
struct hci_conn *conn = container_of(work, struct hci_conn,
|
||||
le_conn_timeout.work);
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
hci_le_create_connection_cancel(conn);
|
||||
}
|
||||
|
||||
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
@@ -410,6 +420,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
|
||||
INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout);
|
||||
INIT_DELAYED_WORK(&conn->auto_accept_work, hci_conn_auto_accept);
|
||||
INIT_DELAYED_WORK(&conn->idle_work, hci_conn_idle);
|
||||
INIT_DELAYED_WORK(&conn->le_conn_timeout, le_conn_timeout);
|
||||
|
||||
atomic_set(&conn->refcnt, 0);
|
||||
|
||||
@@ -442,6 +453,8 @@ int hci_conn_del(struct hci_conn *conn)
|
||||
/* Unacked frames */
|
||||
hdev->acl_cnt += conn->sent;
|
||||
} else if (conn->type == LE_LINK) {
|
||||
cancel_delayed_work_sync(&conn->le_conn_timeout);
|
||||
|
||||
if (hdev->le_pkts)
|
||||
hdev->le_cnt += conn->sent;
|
||||
else
|
||||
@@ -514,6 +527,26 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
|
||||
}
|
||||
EXPORT_SYMBOL(hci_get_route);
|
||||
|
||||
/* This function requires the caller holds hdev->lock */
|
||||
void hci_le_conn_failed(struct hci_conn *conn, u8 status)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
|
||||
conn->state = BT_CLOSED;
|
||||
|
||||
mgmt_connect_failed(hdev, &conn->dst, conn->type, conn->dst_type,
|
||||
status);
|
||||
|
||||
hci_proto_connect_cfm(conn, status);
|
||||
|
||||
hci_conn_del(conn);
|
||||
|
||||
/* Since we may have temporarily stopped the background scanning in
|
||||
* favor of connection establishment, we should restart it.
|
||||
*/
|
||||
hci_update_background_scan(hdev);
|
||||
}
|
||||
|
||||
static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
@@ -530,55 +563,55 @@ static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
|
||||
if (!conn)
|
||||
goto done;
|
||||
|
||||
conn->state = BT_CLOSED;
|
||||
|
||||
mgmt_connect_failed(hdev, &conn->dst, conn->type, conn->dst_type,
|
||||
status);
|
||||
|
||||
hci_proto_connect_cfm(conn, status);
|
||||
|
||||
hci_conn_del(conn);
|
||||
hci_le_conn_failed(conn, status);
|
||||
|
||||
done:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static int hci_create_le_conn(struct hci_conn *conn)
|
||||
static void hci_req_add_le_create_conn(struct hci_request *req,
|
||||
struct hci_conn *conn)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
struct hci_cp_le_create_conn cp;
|
||||
struct hci_request req;
|
||||
int err;
|
||||
|
||||
hci_req_init(&req, hdev);
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
u8 own_addr_type;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
|
||||
/* Update random address, but set require_privacy to false so
|
||||
* that we never connect with an unresolvable address.
|
||||
*/
|
||||
if (hci_update_random_address(req, false, &own_addr_type))
|
||||
return;
|
||||
|
||||
/* Save the address type used for this connnection attempt so we able
|
||||
* to retrieve this information if we need it.
|
||||
*/
|
||||
conn->src_type = own_addr_type;
|
||||
|
||||
cp.scan_interval = cpu_to_le16(hdev->le_scan_interval);
|
||||
cp.scan_window = cpu_to_le16(hdev->le_scan_window);
|
||||
bacpy(&cp.peer_addr, &conn->dst);
|
||||
cp.peer_addr_type = conn->dst_type;
|
||||
cp.own_address_type = conn->src_type;
|
||||
cp.conn_interval_min = cpu_to_le16(hdev->le_conn_min_interval);
|
||||
cp.conn_interval_max = cpu_to_le16(hdev->le_conn_max_interval);
|
||||
cp.supervision_timeout = __constant_cpu_to_le16(0x002a);
|
||||
cp.min_ce_len = __constant_cpu_to_le16(0x0000);
|
||||
cp.max_ce_len = __constant_cpu_to_le16(0x0000);
|
||||
cp.own_address_type = own_addr_type;
|
||||
cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
|
||||
cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
|
||||
cp.supervision_timeout = cpu_to_le16(0x002a);
|
||||
cp.min_ce_len = cpu_to_le16(0x0000);
|
||||
cp.max_ce_len = cpu_to_le16(0x0000);
|
||||
|
||||
hci_req_add(&req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
|
||||
hci_req_add(req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
|
||||
|
||||
err = hci_req_run(&req, create_le_conn_complete);
|
||||
if (err) {
|
||||
hci_conn_del(conn);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
conn->state = BT_CONNECT;
|
||||
}
|
||||
|
||||
static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 dst_type, u8 sec_level, u8 auth_type)
|
||||
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 dst_type, u8 sec_level, u8 auth_type)
|
||||
{
|
||||
struct hci_conn_params *params;
|
||||
struct hci_conn *conn;
|
||||
struct smp_irk *irk;
|
||||
struct hci_request req;
|
||||
int err;
|
||||
|
||||
if (test_bit(HCI_ADVERTISING, &hdev->flags))
|
||||
@@ -607,35 +640,74 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
if (conn)
|
||||
return ERR_PTR(-EBUSY);
|
||||
|
||||
/* When given an identity address with existing identity
|
||||
* resolving key, the connection needs to be established
|
||||
* to a resolvable random address.
|
||||
*
|
||||
* This uses the cached random resolvable address from
|
||||
* a previous scan. When no cached address is available,
|
||||
* try connecting to the identity address instead.
|
||||
*
|
||||
* Storing the resolvable random address is required here
|
||||
* to handle connection failures. The address will later
|
||||
* be resolved back into the original identity address
|
||||
* from the connect request.
|
||||
*/
|
||||
irk = hci_find_irk_by_addr(hdev, dst, dst_type);
|
||||
if (irk && bacmp(&irk->rpa, BDADDR_ANY)) {
|
||||
dst = &irk->rpa;
|
||||
dst_type = ADDR_LE_DEV_RANDOM;
|
||||
}
|
||||
|
||||
conn = hci_conn_add(hdev, LE_LINK, dst);
|
||||
if (!conn)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (dst_type == BDADDR_LE_PUBLIC)
|
||||
conn->dst_type = ADDR_LE_DEV_PUBLIC;
|
||||
else
|
||||
conn->dst_type = ADDR_LE_DEV_RANDOM;
|
||||
conn->dst_type = dst_type;
|
||||
|
||||
conn->src_type = hdev->own_addr_type;
|
||||
|
||||
conn->state = BT_CONNECT;
|
||||
conn->out = true;
|
||||
conn->link_mode |= HCI_LM_MASTER;
|
||||
conn->sec_level = BT_SECURITY_LOW;
|
||||
conn->pending_sec_level = sec_level;
|
||||
conn->auth_type = auth_type;
|
||||
|
||||
err = hci_create_le_conn(conn);
|
||||
if (err)
|
||||
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
|
||||
if (params) {
|
||||
conn->le_conn_min_interval = params->conn_min_interval;
|
||||
conn->le_conn_max_interval = params->conn_max_interval;
|
||||
} else {
|
||||
conn->le_conn_min_interval = hdev->le_conn_min_interval;
|
||||
conn->le_conn_max_interval = hdev->le_conn_max_interval;
|
||||
}
|
||||
|
||||
hci_req_init(&req, hdev);
|
||||
|
||||
/* If controller is scanning, we stop it since some controllers are
|
||||
* not able to scan and connect at the same time. Also set the
|
||||
* HCI_LE_SCAN_INTERRUPTED flag so that the command complete
|
||||
* handler for scan disabling knows to set the correct discovery
|
||||
* state.
|
||||
*/
|
||||
if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
|
||||
hci_req_add_le_scan_disable(&req);
|
||||
set_bit(HCI_LE_SCAN_INTERRUPTED, &hdev->dev_flags);
|
||||
}
|
||||
|
||||
hci_req_add_le_create_conn(&req, conn);
|
||||
|
||||
err = hci_req_run(&req, create_le_conn_complete);
|
||||
if (err) {
|
||||
hci_conn_del(conn);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
done:
|
||||
hci_conn_hold(conn);
|
||||
return conn;
|
||||
}
|
||||
|
||||
static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 sec_level, u8 auth_type)
|
||||
struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 sec_level, u8 auth_type)
|
||||
{
|
||||
struct hci_conn *acl;
|
||||
|
||||
@@ -704,27 +776,22 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
return sco;
|
||||
}
|
||||
|
||||
/* Create SCO, ACL or LE connection. */
|
||||
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
__u8 dst_type, __u8 sec_level, __u8 auth_type)
|
||||
{
|
||||
BT_DBG("%s dst %pMR type 0x%x", hdev->name, dst, type);
|
||||
|
||||
switch (type) {
|
||||
case LE_LINK:
|
||||
return hci_connect_le(hdev, dst, dst_type, sec_level, auth_type);
|
||||
case ACL_LINK:
|
||||
return hci_connect_acl(hdev, dst, sec_level, auth_type);
|
||||
}
|
||||
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
/* Check link security requirement */
|
||||
int hci_conn_check_link_mode(struct hci_conn *conn)
|
||||
{
|
||||
BT_DBG("hcon %p", conn);
|
||||
|
||||
/* In Secure Connections Only mode, it is required that Secure
|
||||
* Connections is used and the link is encrypted with AES-CCM
|
||||
* using a P-256 authenticated combination key.
|
||||
*/
|
||||
if (test_bit(HCI_SC_ONLY, &conn->hdev->flags)) {
|
||||
if (!hci_conn_sc_enabled(conn) ||
|
||||
!test_bit(HCI_CONN_AES_CCM, &conn->flags) ||
|
||||
conn->key_type != HCI_LK_AUTH_COMBINATION_P256)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hci_conn_ssp_enabled(conn) && !(conn->link_mode & HCI_LM_ENCRYPT))
|
||||
return 0;
|
||||
|
||||
@@ -800,14 +867,23 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
||||
if (!(conn->link_mode & HCI_LM_AUTH))
|
||||
goto auth;
|
||||
|
||||
/* An authenticated combination key has sufficient security for any
|
||||
security level. */
|
||||
if (conn->key_type == HCI_LK_AUTH_COMBINATION)
|
||||
/* An authenticated FIPS approved combination key has sufficient
|
||||
* security for security level 4. */
|
||||
if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256 &&
|
||||
sec_level == BT_SECURITY_FIPS)
|
||||
goto encrypt;
|
||||
|
||||
/* An authenticated combination key has sufficient security for
|
||||
security level 3. */
|
||||
if ((conn->key_type == HCI_LK_AUTH_COMBINATION_P192 ||
|
||||
conn->key_type == HCI_LK_AUTH_COMBINATION_P256) &&
|
||||
sec_level == BT_SECURITY_HIGH)
|
||||
goto encrypt;
|
||||
|
||||
/* An unauthenticated combination key has sufficient security for
|
||||
security level 1 and 2. */
|
||||
if (conn->key_type == HCI_LK_UNAUTH_COMBINATION &&
|
||||
if ((conn->key_type == HCI_LK_UNAUTH_COMBINATION_P192 ||
|
||||
conn->key_type == HCI_LK_UNAUTH_COMBINATION_P256) &&
|
||||
(sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW))
|
||||
goto encrypt;
|
||||
|
||||
@@ -816,7 +892,8 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
||||
is generated using maximum PIN code length (16).
|
||||
For pre 2.1 units. */
|
||||
if (conn->key_type == HCI_LK_COMBINATION &&
|
||||
(sec_level != BT_SECURITY_HIGH || conn->pin_length == 16))
|
||||
(sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW ||
|
||||
conn->pin_length == 16))
|
||||
goto encrypt;
|
||||
|
||||
auth:
|
||||
@@ -840,13 +917,17 @@ int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level)
|
||||
{
|
||||
BT_DBG("hcon %p", conn);
|
||||
|
||||
if (sec_level != BT_SECURITY_HIGH)
|
||||
return 1; /* Accept if non-secure is required */
|
||||
|
||||
if (conn->sec_level == BT_SECURITY_HIGH)
|
||||
/* Accept if non-secure or higher security level is required */
|
||||
if (sec_level != BT_SECURITY_HIGH && sec_level != BT_SECURITY_FIPS)
|
||||
return 1;
|
||||
|
||||
return 0; /* Reject not secure link */
|
||||
/* Accept if secure or higher security level is already present */
|
||||
if (conn->sec_level == BT_SECURITY_HIGH ||
|
||||
conn->sec_level == BT_SECURITY_FIPS)
|
||||
return 1;
|
||||
|
||||
/* Reject not secure link */
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hci_conn_check_secure);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -199,6 +199,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
memset(hdev->scan_rsp_data, 0, sizeof(hdev->scan_rsp_data));
|
||||
hdev->scan_rsp_data_len = 0;
|
||||
|
||||
hdev->le_scan_type = LE_SCAN_PASSIVE;
|
||||
|
||||
hdev->ssp_debug_mode = 0;
|
||||
}
|
||||
|
||||
@@ -461,6 +463,34 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_cc_write_sc_support(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
u8 status = *((u8 *) skb->data);
|
||||
struct hci_cp_write_sc_support *sent;
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SC_SUPPORT);
|
||||
if (!sent)
|
||||
return;
|
||||
|
||||
if (!status) {
|
||||
if (sent->support)
|
||||
hdev->features[1][0] |= LMP_HOST_SC;
|
||||
else
|
||||
hdev->features[1][0] &= ~LMP_HOST_SC;
|
||||
}
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->dev_flags))
|
||||
mgmt_sc_enable_complete(hdev, sent->support, status);
|
||||
else if (!status) {
|
||||
if (sent->support)
|
||||
set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
|
||||
else
|
||||
clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_read_local_version *rp = (void *) skb->data;
|
||||
@@ -904,16 +934,50 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
static void hci_cc_read_local_oob_data(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
mgmt_read_local_oob_data_reply_complete(hdev, rp->hash,
|
||||
rp->randomizer, rp->status);
|
||||
mgmt_read_local_oob_data_complete(hdev, rp->hash, rp->randomizer,
|
||||
NULL, NULL, rp->status);
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_read_local_oob_ext_data(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
mgmt_read_local_oob_data_complete(hdev, rp->hash192, rp->randomizer192,
|
||||
rp->hash256, rp->randomizer256,
|
||||
rp->status);
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
|
||||
static void hci_cc_le_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
bdaddr_t *sent;
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_RANDOM_ADDR);
|
||||
if (!sent)
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!status)
|
||||
bacpy(&hdev->random_addr, sent);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
@@ -929,12 +993,27 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!status) {
|
||||
if (*sent)
|
||||
set_bit(HCI_ADVERTISING, &hdev->dev_flags);
|
||||
else
|
||||
clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
|
||||
}
|
||||
if (!status)
|
||||
mgmt_advertising(hdev, *sent);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_cp_le_set_scan_param *cp;
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_PARAM);
|
||||
if (!cp)
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!status)
|
||||
hdev->le_scan_type = cp->type;
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
@@ -960,7 +1039,19 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
||||
break;
|
||||
|
||||
case LE_SCAN_DISABLE:
|
||||
/* Cancel this timer so that we don't try to disable scanning
|
||||
* when it's already disabled.
|
||||
*/
|
||||
cancel_delayed_work(&hdev->le_scan_disable);
|
||||
|
||||
clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
|
||||
/* The HCI_LE_SCAN_INTERRUPTED flag indicates that we
|
||||
* interrupted scanning due to a connect request. Mark
|
||||
* therefore discovery as stopped.
|
||||
*/
|
||||
if (test_and_clear_bit(HCI_LE_SCAN_INTERRUPTED,
|
||||
&hdev->dev_flags))
|
||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -980,6 +1071,49 @@ static void hci_cc_le_read_white_list_size(struct hci_dev *hdev,
|
||||
hdev->le_white_list_size = rp->size;
|
||||
}
|
||||
|
||||
static void hci_cc_le_clear_white_list(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
if (!status)
|
||||
hci_white_list_clear(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_le_add_to_white_list(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_cp_le_add_to_white_list *sent;
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_WHITE_LIST);
|
||||
if (!sent)
|
||||
return;
|
||||
|
||||
if (!status)
|
||||
hci_white_list_add(hdev, &sent->bdaddr, sent->bdaddr_type);
|
||||
}
|
||||
|
||||
static void hci_cc_le_del_from_white_list(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_cp_le_del_from_white_list *sent;
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_WHITE_LIST);
|
||||
if (!sent)
|
||||
return;
|
||||
|
||||
if (!status)
|
||||
hci_white_list_del(hdev, &sent->bdaddr, sent->bdaddr_type);
|
||||
}
|
||||
|
||||
static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@@ -1020,6 +1154,25 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_cp_le_set_adv_param *cp;
|
||||
u8 status = *((u8 *) skb->data);
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
if (status)
|
||||
return;
|
||||
|
||||
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_PARAM);
|
||||
if (!cp)
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hdev->adv_addr_type = cp->own_address_type;
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@@ -1185,9 +1338,12 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
|
||||
return 0;
|
||||
|
||||
/* Only request authentication for SSP connections or non-SSP
|
||||
* devices with sec_level HIGH or if MITM protection is requested */
|
||||
* devices with sec_level MEDIUM or HIGH or if MITM protection
|
||||
* is requested.
|
||||
*/
|
||||
if (!hci_conn_ssp_enabled(conn) && !(conn->auth_type & 0x01) &&
|
||||
conn->pending_sec_level != BT_SECURITY_HIGH)
|
||||
conn->pending_sec_level != BT_SECURITY_HIGH &&
|
||||
conn->pending_sec_level != BT_SECURITY_MEDIUM)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@@ -1518,6 +1674,87 @@ static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
|
||||
amp_write_remote_assoc(hdev, cp->phy_handle);
|
||||
}
|
||||
|
||||
static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status)
|
||||
{
|
||||
struct hci_cp_le_create_conn *cp;
|
||||
struct hci_conn *conn;
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
/* All connection failure handling is taken care of by the
|
||||
* hci_le_conn_failed function which is triggered by the HCI
|
||||
* request completion callbacks used for connecting.
|
||||
*/
|
||||
if (status)
|
||||
return;
|
||||
|
||||
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN);
|
||||
if (!cp)
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
|
||||
if (!conn)
|
||||
goto unlock;
|
||||
|
||||
/* Store the initiator and responder address information which
|
||||
* is needed for SMP. These values will not change during the
|
||||
* lifetime of the connection.
|
||||
*/
|
||||
conn->init_addr_type = cp->own_address_type;
|
||||
if (cp->own_address_type == ADDR_LE_DEV_RANDOM)
|
||||
bacpy(&conn->init_addr, &hdev->random_addr);
|
||||
else
|
||||
bacpy(&conn->init_addr, &hdev->bdaddr);
|
||||
|
||||
conn->resp_addr_type = cp->peer_addr_type;
|
||||
bacpy(&conn->resp_addr, &cp->peer_addr);
|
||||
|
||||
/* We don't want the connection attempt to stick around
|
||||
* indefinitely since LE doesn't have a page timeout concept
|
||||
* like BR/EDR. Set a timer for any connection that doesn't use
|
||||
* the white list for connecting.
|
||||
*/
|
||||
if (cp->filter_policy == HCI_LE_USE_PEER_ADDR)
|
||||
queue_delayed_work(conn->hdev->workqueue,
|
||||
&conn->le_conn_timeout,
|
||||
HCI_LE_CONN_TIMEOUT);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
|
||||
{
|
||||
struct hci_cp_le_start_enc *cp;
|
||||
struct hci_conn *conn;
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
if (!status)
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_START_ENC);
|
||||
if (!cp)
|
||||
goto unlock;
|
||||
|
||||
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
|
||||
if (!conn)
|
||||
goto unlock;
|
||||
|
||||
if (conn->state != BT_CONNECTED)
|
||||
goto unlock;
|
||||
|
||||
hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
|
||||
hci_conn_drop(conn);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
@@ -1659,7 +1896,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
} else {
|
||||
conn->state = BT_CLOSED;
|
||||
if (conn->type == ACL_LINK)
|
||||
mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
|
||||
mgmt_connect_failed(hdev, &conn->dst, conn->type,
|
||||
conn->dst_type, ev->status);
|
||||
}
|
||||
|
||||
@@ -1738,9 +1975,9 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
bacpy(&cp.bdaddr, &ev->bdaddr);
|
||||
cp.pkt_type = cpu_to_le16(conn->pkt_type);
|
||||
|
||||
cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
||||
cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
||||
cp.max_latency = __constant_cpu_to_le16(0xffff);
|
||||
cp.tx_bandwidth = cpu_to_le32(0x00001f40);
|
||||
cp.rx_bandwidth = cpu_to_le32(0x00001f40);
|
||||
cp.max_latency = cpu_to_le16(0xffff);
|
||||
cp.content_format = cpu_to_le16(hdev->voice_setting);
|
||||
cp.retrans_effort = 0xff;
|
||||
|
||||
@@ -1780,7 +2017,9 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_disconn_complete *ev = (void *) skb->data;
|
||||
u8 reason = hci_to_mgmt_reason(ev->reason);
|
||||
struct hci_conn_params *params;
|
||||
struct hci_conn *conn;
|
||||
bool mgmt_connected;
|
||||
u8 type;
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
|
||||
@@ -1799,13 +2038,30 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
conn->state = BT_CLOSED;
|
||||
|
||||
if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
|
||||
mgmt_device_disconnected(hdev, &conn->dst, conn->type,
|
||||
conn->dst_type, reason);
|
||||
mgmt_connected = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
|
||||
mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type,
|
||||
reason, mgmt_connected);
|
||||
|
||||
if (conn->type == ACL_LINK && conn->flush_key)
|
||||
hci_remove_link_key(hdev, &conn->dst);
|
||||
|
||||
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
|
||||
if (params) {
|
||||
switch (params->auto_connect) {
|
||||
case HCI_AUTO_CONN_LINK_LOSS:
|
||||
if (ev->reason != HCI_ERROR_CONNECTION_TIMEOUT)
|
||||
break;
|
||||
/* Fall through */
|
||||
|
||||
case HCI_AUTO_CONN_ALWAYS:
|
||||
hci_pend_le_conn_add(hdev, &conn->dst, conn->dst_type);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
type = conn->type;
|
||||
|
||||
hci_proto_disconn_cfm(conn, ev->reason);
|
||||
@@ -1943,34 +2199,57 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
|
||||
if (conn) {
|
||||
if (!ev->status) {
|
||||
if (ev->encrypt) {
|
||||
/* Encryption implies authentication */
|
||||
conn->link_mode |= HCI_LM_AUTH;
|
||||
conn->link_mode |= HCI_LM_ENCRYPT;
|
||||
conn->sec_level = conn->pending_sec_level;
|
||||
} else
|
||||
conn->link_mode &= ~HCI_LM_ENCRYPT;
|
||||
if (!conn)
|
||||
goto unlock;
|
||||
|
||||
if (!ev->status) {
|
||||
if (ev->encrypt) {
|
||||
/* Encryption implies authentication */
|
||||
conn->link_mode |= HCI_LM_AUTH;
|
||||
conn->link_mode |= HCI_LM_ENCRYPT;
|
||||
conn->sec_level = conn->pending_sec_level;
|
||||
|
||||
/* P-256 authentication key implies FIPS */
|
||||
if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256)
|
||||
conn->link_mode |= HCI_LM_FIPS;
|
||||
|
||||
if ((conn->type == ACL_LINK && ev->encrypt == 0x02) ||
|
||||
conn->type == LE_LINK)
|
||||
set_bit(HCI_CONN_AES_CCM, &conn->flags);
|
||||
} else {
|
||||
conn->link_mode &= ~HCI_LM_ENCRYPT;
|
||||
clear_bit(HCI_CONN_AES_CCM, &conn->flags);
|
||||
}
|
||||
}
|
||||
|
||||
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
|
||||
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
|
||||
|
||||
if (ev->status && conn->state == BT_CONNECTED) {
|
||||
hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
|
||||
if (ev->status && conn->state == BT_CONNECTED) {
|
||||
hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
|
||||
hci_conn_drop(conn);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (conn->state == BT_CONFIG) {
|
||||
if (!ev->status)
|
||||
conn->state = BT_CONNECTED;
|
||||
|
||||
/* In Secure Connections Only mode, do not allow any
|
||||
* connections that are not encrypted with AES-CCM
|
||||
* using a P-256 authenticated combination key.
|
||||
*/
|
||||
if (test_bit(HCI_SC_ONLY, &hdev->dev_flags) &&
|
||||
(!test_bit(HCI_CONN_AES_CCM, &conn->flags) ||
|
||||
conn->key_type != HCI_LK_AUTH_COMBINATION_P256)) {
|
||||
hci_proto_connect_cfm(conn, HCI_ERROR_AUTH_FAILURE);
|
||||
hci_conn_drop(conn);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (conn->state == BT_CONFIG) {
|
||||
if (!ev->status)
|
||||
conn->state = BT_CONNECTED;
|
||||
|
||||
hci_proto_connect_cfm(conn, ev->status);
|
||||
hci_conn_drop(conn);
|
||||
} else
|
||||
hci_encrypt_cfm(conn, ev->status, ev->encrypt);
|
||||
}
|
||||
hci_proto_connect_cfm(conn, ev->status);
|
||||
hci_conn_drop(conn);
|
||||
} else
|
||||
hci_encrypt_cfm(conn, ev->status, ev->encrypt);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
@@ -2144,6 +2423,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_cc_write_ssp_mode(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_WRITE_SC_SUPPORT:
|
||||
hci_cc_write_sc_support(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_READ_LOCAL_VERSION:
|
||||
hci_cc_read_local_version(hdev, skb);
|
||||
break;
|
||||
@@ -2213,7 +2496,11 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
break;
|
||||
|
||||
case HCI_OP_READ_LOCAL_OOB_DATA:
|
||||
hci_cc_read_local_oob_data_reply(hdev, skb);
|
||||
hci_cc_read_local_oob_data(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_READ_LOCAL_OOB_EXT_DATA:
|
||||
hci_cc_read_local_oob_ext_data(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_READ_BUFFER_SIZE:
|
||||
@@ -2244,10 +2531,18 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_cc_user_passkey_neg_reply(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_SET_RANDOM_ADDR:
|
||||
hci_cc_le_set_random_addr(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_SET_ADV_ENABLE:
|
||||
hci_cc_le_set_adv_enable(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_SET_SCAN_PARAM:
|
||||
hci_cc_le_set_scan_param(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_SET_SCAN_ENABLE:
|
||||
hci_cc_le_set_scan_enable(hdev, skb);
|
||||
break;
|
||||
@@ -2256,6 +2551,18 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_cc_le_read_white_list_size(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_CLEAR_WHITE_LIST:
|
||||
hci_cc_le_clear_white_list(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_ADD_TO_WHITE_LIST:
|
||||
hci_cc_le_add_to_white_list(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_DEL_FROM_WHITE_LIST:
|
||||
hci_cc_le_del_from_white_list(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_READ_SUPPORTED_STATES:
|
||||
hci_cc_le_read_supported_states(hdev, skb);
|
||||
break;
|
||||
@@ -2264,6 +2571,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_cc_write_le_host_supported(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_SET_ADV_PARAM:
|
||||
hci_cc_set_adv_param(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_WRITE_REMOTE_AMP_ASSOC:
|
||||
hci_cc_write_remote_amp_assoc(hdev, skb);
|
||||
break;
|
||||
@@ -2351,6 +2662,14 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_cs_accept_phylink(hdev, ev->status);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_CREATE_CONN:
|
||||
hci_cs_le_create_conn(hdev, ev->status);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_START_ENC:
|
||||
hci_cs_le_start_enc(hdev, ev->status);
|
||||
break;
|
||||
|
||||
default:
|
||||
BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
|
||||
break;
|
||||
@@ -2630,7 +2949,8 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
|
||||
if (conn) {
|
||||
if (key->type == HCI_LK_UNAUTH_COMBINATION &&
|
||||
if ((key->type == HCI_LK_UNAUTH_COMBINATION_P192 ||
|
||||
key->type == HCI_LK_UNAUTH_COMBINATION_P256) &&
|
||||
conn->auth_type != 0xff && (conn->auth_type & 0x01)) {
|
||||
BT_DBG("%s ignoring unauthenticated key", hdev->name);
|
||||
goto not_found;
|
||||
@@ -2844,6 +3164,9 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev,
|
||||
* features do not indicate SSP support */
|
||||
clear_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
|
||||
}
|
||||
|
||||
if (ev->features[0] & LMP_HOST_SC)
|
||||
set_bit(HCI_CONN_SC_ENABLED, &conn->flags);
|
||||
}
|
||||
|
||||
if (conn->state != BT_CONFIG)
|
||||
@@ -2905,6 +3228,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
|
||||
case 0x1c: /* SCO interval rejected */
|
||||
case 0x1a: /* Unsupported Remote Feature */
|
||||
case 0x1f: /* Unspecified error */
|
||||
case 0x20: /* Unsupported LMP Parameter value */
|
||||
if (conn->out) {
|
||||
conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
|
||||
(hdev->esco_type & EDR_ESCO_MASK);
|
||||
@@ -3194,8 +3518,8 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev,
|
||||
}
|
||||
|
||||
confirm:
|
||||
mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0, ev->passkey,
|
||||
confirm_hint);
|
||||
mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0,
|
||||
le32_to_cpu(ev->passkey), confirm_hint);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
@@ -3337,20 +3661,36 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
|
||||
|
||||
data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
|
||||
if (data) {
|
||||
struct hci_cp_remote_oob_data_reply cp;
|
||||
if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
|
||||
struct hci_cp_remote_oob_ext_data_reply cp;
|
||||
|
||||
bacpy(&cp.bdaddr, &ev->bdaddr);
|
||||
memcpy(cp.hash, data->hash, sizeof(cp.hash));
|
||||
memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
|
||||
bacpy(&cp.bdaddr, &ev->bdaddr);
|
||||
memcpy(cp.hash192, data->hash192, sizeof(cp.hash192));
|
||||
memcpy(cp.randomizer192, data->randomizer192,
|
||||
sizeof(cp.randomizer192));
|
||||
memcpy(cp.hash256, data->hash256, sizeof(cp.hash256));
|
||||
memcpy(cp.randomizer256, data->randomizer256,
|
||||
sizeof(cp.randomizer256));
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp),
|
||||
&cp);
|
||||
hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_EXT_DATA_REPLY,
|
||||
sizeof(cp), &cp);
|
||||
} else {
|
||||
struct hci_cp_remote_oob_data_reply cp;
|
||||
|
||||
bacpy(&cp.bdaddr, &ev->bdaddr);
|
||||
memcpy(cp.hash, data->hash192, sizeof(cp.hash));
|
||||
memcpy(cp.randomizer, data->randomizer192,
|
||||
sizeof(cp.randomizer));
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY,
|
||||
sizeof(cp), &cp);
|
||||
}
|
||||
} else {
|
||||
struct hci_cp_remote_oob_data_neg_reply cp;
|
||||
|
||||
bacpy(&cp.bdaddr, &ev->bdaddr);
|
||||
hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp),
|
||||
&cp);
|
||||
hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY,
|
||||
sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
unlock:
|
||||
@@ -3484,6 +3824,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_le_conn_complete *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
struct smp_irk *irk;
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
|
||||
|
||||
@@ -3514,19 +3855,70 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
conn->out = true;
|
||||
conn->link_mode |= HCI_LM_MASTER;
|
||||
}
|
||||
|
||||
/* If we didn't have a hci_conn object previously
|
||||
* but we're in master role this must be something
|
||||
* initiated using a white list. Since white list based
|
||||
* connections are not "first class citizens" we don't
|
||||
* have full tracking of them. Therefore, we go ahead
|
||||
* with a "best effort" approach of determining the
|
||||
* initiator address based on the HCI_PRIVACY flag.
|
||||
*/
|
||||
if (conn->out) {
|
||||
conn->resp_addr_type = ev->bdaddr_type;
|
||||
bacpy(&conn->resp_addr, &ev->bdaddr);
|
||||
if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) {
|
||||
conn->init_addr_type = ADDR_LE_DEV_RANDOM;
|
||||
bacpy(&conn->init_addr, &hdev->rpa);
|
||||
} else {
|
||||
hci_copy_identity_address(hdev,
|
||||
&conn->init_addr,
|
||||
&conn->init_addr_type);
|
||||
}
|
||||
} else {
|
||||
/* Set the responder (our side) address type based on
|
||||
* the advertising address type.
|
||||
*/
|
||||
conn->resp_addr_type = hdev->adv_addr_type;
|
||||
if (hdev->adv_addr_type == ADDR_LE_DEV_RANDOM)
|
||||
bacpy(&conn->resp_addr, &hdev->random_addr);
|
||||
else
|
||||
bacpy(&conn->resp_addr, &hdev->bdaddr);
|
||||
|
||||
conn->init_addr_type = ev->bdaddr_type;
|
||||
bacpy(&conn->init_addr, &ev->bdaddr);
|
||||
}
|
||||
} else {
|
||||
cancel_delayed_work(&conn->le_conn_timeout);
|
||||
}
|
||||
|
||||
/* Ensure that the hci_conn contains the identity address type
|
||||
* regardless of which address the connection was made with.
|
||||
*/
|
||||
hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
|
||||
|
||||
/* Lookup the identity address from the stored connection
|
||||
* address and address type.
|
||||
*
|
||||
* When establishing connections to an identity address, the
|
||||
* connection procedure will store the resolvable random
|
||||
* address first. Now if it can be converted back into the
|
||||
* identity address, start using the identity address from
|
||||
* now on.
|
||||
*/
|
||||
irk = hci_get_irk(hdev, &conn->dst, conn->dst_type);
|
||||
if (irk) {
|
||||
bacpy(&conn->dst, &irk->bdaddr);
|
||||
conn->dst_type = irk->addr_type;
|
||||
}
|
||||
|
||||
if (ev->status) {
|
||||
mgmt_connect_failed(hdev, &conn->dst, conn->type,
|
||||
conn->dst_type, ev->status);
|
||||
hci_proto_connect_cfm(conn, ev->status);
|
||||
conn->state = BT_CLOSED;
|
||||
hci_conn_del(conn);
|
||||
hci_le_conn_failed(conn, ev->status);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
|
||||
mgmt_device_connected(hdev, &ev->bdaddr, conn->type,
|
||||
mgmt_device_connected(hdev, &conn->dst, conn->type,
|
||||
conn->dst_type, 0, NULL, 0, NULL);
|
||||
|
||||
conn->sec_level = BT_SECURITY_LOW;
|
||||
@@ -3540,25 +3932,73 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
hci_proto_connect_cfm(conn, ev->status);
|
||||
|
||||
hci_pend_le_conn_del(hdev, &conn->dst, conn->dst_type);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
/* This function requires the caller holds hdev->lock */
|
||||
static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
|
||||
u8 addr_type)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
struct smp_irk *irk;
|
||||
|
||||
/* If this is a resolvable address, we should resolve it and then
|
||||
* update address and address type variables.
|
||||
*/
|
||||
irk = hci_get_irk(hdev, addr, addr_type);
|
||||
if (irk) {
|
||||
addr = &irk->bdaddr;
|
||||
addr_type = irk->addr_type;
|
||||
}
|
||||
|
||||
if (!hci_pend_le_conn_lookup(hdev, addr, addr_type))
|
||||
return;
|
||||
|
||||
conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW,
|
||||
HCI_AT_NO_BONDING);
|
||||
if (!IS_ERR(conn))
|
||||
return;
|
||||
|
||||
switch (PTR_ERR(conn)) {
|
||||
case -EBUSY:
|
||||
/* If hci_connect() returns -EBUSY it means there is already
|
||||
* an LE connection attempt going on. Since controllers don't
|
||||
* support more than one connection attempt at the time, we
|
||||
* don't consider this an error case.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
BT_DBG("Failed to connect: err %ld", PTR_ERR(conn));
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
u8 num_reports = skb->data[0];
|
||||
void *ptr = &skb->data[1];
|
||||
s8 rssi;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
while (num_reports--) {
|
||||
struct hci_ev_le_advertising_info *ev = ptr;
|
||||
|
||||
if (ev->evt_type == LE_ADV_IND ||
|
||||
ev->evt_type == LE_ADV_DIRECT_IND)
|
||||
check_pending_le_conn(hdev, &ev->bdaddr,
|
||||
ev->bdaddr_type);
|
||||
|
||||
rssi = ev->data[ev->length];
|
||||
mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type,
|
||||
NULL, rssi, 0, 1, ev->data, ev->length);
|
||||
|
||||
ptr += sizeof(*ev) + ev->length + 1;
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
@@ -3577,7 +4017,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
if (conn == NULL)
|
||||
goto not_found;
|
||||
|
||||
ltk = hci_find_ltk(hdev, ev->ediv, ev->random);
|
||||
ltk = hci_find_ltk(hdev, ev->ediv, ev->rand, conn->out);
|
||||
if (ltk == NULL)
|
||||
goto not_found;
|
||||
|
||||
@@ -3593,7 +4033,13 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
|
||||
|
||||
if (ltk->type & HCI_SMP_STK) {
|
||||
/* Ref. Bluetooth Core SPEC pages 1975 and 2004. STK is a
|
||||
* temporary key used to encrypt a connection following
|
||||
* pairing. It is used during the Encrypted Session Setup to
|
||||
* distribute the keys. Later, security can be re-established
|
||||
* using a distributed LTK.
|
||||
*/
|
||||
if (ltk->type == HCI_SMP_STK_SLAVE) {
|
||||
list_del(<k->list);
|
||||
kfree(ltk);
|
||||
}
|
||||
|
@@ -211,22 +211,22 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
switch (bt_cb(skb)->pkt_type) {
|
||||
case HCI_COMMAND_PKT:
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_COMMAND_PKT);
|
||||
opcode = cpu_to_le16(HCI_MON_COMMAND_PKT);
|
||||
break;
|
||||
case HCI_EVENT_PKT:
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_EVENT_PKT);
|
||||
opcode = cpu_to_le16(HCI_MON_EVENT_PKT);
|
||||
break;
|
||||
case HCI_ACLDATA_PKT:
|
||||
if (bt_cb(skb)->incoming)
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_ACL_RX_PKT);
|
||||
opcode = cpu_to_le16(HCI_MON_ACL_RX_PKT);
|
||||
else
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_ACL_TX_PKT);
|
||||
opcode = cpu_to_le16(HCI_MON_ACL_TX_PKT);
|
||||
break;
|
||||
case HCI_SCODATA_PKT:
|
||||
if (bt_cb(skb)->incoming)
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_SCO_RX_PKT);
|
||||
opcode = cpu_to_le16(HCI_MON_SCO_RX_PKT);
|
||||
else
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_SCO_TX_PKT);
|
||||
opcode = cpu_to_le16(HCI_MON_SCO_TX_PKT);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@@ -319,7 +319,7 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
|
||||
bacpy(&ni->bdaddr, &hdev->bdaddr);
|
||||
memcpy(ni->name, hdev->name, 8);
|
||||
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_NEW_INDEX);
|
||||
opcode = cpu_to_le16(HCI_MON_NEW_INDEX);
|
||||
break;
|
||||
|
||||
case HCI_DEV_UNREG:
|
||||
@@ -327,7 +327,7 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_DEL_INDEX);
|
||||
opcode = cpu_to_le16(HCI_MON_DEL_INDEX);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -716,6 +716,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
|
||||
err = hci_dev_open(hdev->id);
|
||||
if (err) {
|
||||
clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags);
|
||||
mgmt_index_added(hdev);
|
||||
hci_dev_put(hdev);
|
||||
goto done;
|
||||
}
|
||||
|
@@ -49,14 +49,7 @@ static struct attribute *bt_link_attrs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group bt_link_group = {
|
||||
.attrs = bt_link_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *bt_link_groups[] = {
|
||||
&bt_link_group,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(bt_link);
|
||||
|
||||
static void bt_link_release(struct device *dev)
|
||||
{
|
||||
@@ -182,14 +175,7 @@ static struct attribute *bt_host_attrs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group bt_host_group = {
|
||||
.attrs = bt_host_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *bt_host_groups[] = {
|
||||
&bt_host_group,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(bt_host);
|
||||
|
||||
static void bt_host_release(struct device *dev)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -36,8 +36,6 @@
|
||||
|
||||
#include "smp.h"
|
||||
|
||||
bool enable_lecoc;
|
||||
|
||||
static struct bt_sock_list l2cap_sk_list = {
|
||||
.lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
|
||||
};
|
||||
@@ -101,12 +99,19 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
|
||||
if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
|
||||
return -EINVAL;
|
||||
|
||||
if (la.l2_cid) {
|
||||
/* When the socket gets created it defaults to
|
||||
* CHAN_CONN_ORIENTED, so we need to overwrite the
|
||||
* default here.
|
||||
*/
|
||||
chan->chan_type = L2CAP_CHAN_FIXED;
|
||||
chan->omtu = L2CAP_DEFAULT_MTU;
|
||||
}
|
||||
|
||||
if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
|
||||
if (!enable_lecoc && la.l2_psm)
|
||||
return -EINVAL;
|
||||
/* We only allow ATT user space socket */
|
||||
if (la.l2_cid &&
|
||||
la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT))
|
||||
la.l2_cid != cpu_to_le16(L2CAP_CID_ATT))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -204,7 +209,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
|
||||
* ATT. Anything else is an invalid combination.
|
||||
*/
|
||||
if (chan->scid != L2CAP_CID_ATT ||
|
||||
la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT))
|
||||
la.l2_cid != cpu_to_le16(L2CAP_CID_ATT))
|
||||
return -EINVAL;
|
||||
|
||||
/* We don't have the hdev available here to make a
|
||||
@@ -220,11 +225,9 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
|
||||
return -EINVAL;
|
||||
|
||||
if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
|
||||
if (!enable_lecoc && la.l2_psm)
|
||||
return -EINVAL;
|
||||
/* We only allow ATT user space socket */
|
||||
if (la.l2_cid &&
|
||||
la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT))
|
||||
la.l2_cid != cpu_to_le16(L2CAP_CID_ATT))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -357,17 +360,21 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr,
|
||||
|
||||
BT_DBG("sock %p, sk %p", sock, sk);
|
||||
|
||||
if (peer && sk->sk_state != BT_CONNECTED &&
|
||||
sk->sk_state != BT_CONNECT && sk->sk_state != BT_CONNECT2)
|
||||
return -ENOTCONN;
|
||||
|
||||
memset(la, 0, sizeof(struct sockaddr_l2));
|
||||
addr->sa_family = AF_BLUETOOTH;
|
||||
*len = sizeof(struct sockaddr_l2);
|
||||
|
||||
la->l2_psm = chan->psm;
|
||||
|
||||
if (peer) {
|
||||
la->l2_psm = chan->psm;
|
||||
bacpy(&la->l2_bdaddr, &chan->dst);
|
||||
la->l2_cid = cpu_to_le16(chan->dcid);
|
||||
la->l2_bdaddr_type = chan->dst_type;
|
||||
} else {
|
||||
la->l2_psm = chan->sport;
|
||||
bacpy(&la->l2_bdaddr, &chan->src);
|
||||
la->l2_cid = cpu_to_le16(chan->scid);
|
||||
la->l2_bdaddr_type = chan->src_type;
|
||||
@@ -432,6 +439,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
|
||||
opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
|
||||
L2CAP_LM_SECURE;
|
||||
break;
|
||||
case BT_SECURITY_FIPS:
|
||||
opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
|
||||
L2CAP_LM_SECURE | L2CAP_LM_FIPS;
|
||||
break;
|
||||
default:
|
||||
opt = 0;
|
||||
break;
|
||||
@@ -445,6 +456,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
|
||||
|
||||
if (put_user(opt, (u32 __user *) optval))
|
||||
err = -EFAULT;
|
||||
|
||||
break;
|
||||
|
||||
case L2CAP_CONNINFO:
|
||||
@@ -499,6 +511,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
|
||||
switch (optname) {
|
||||
case BT_SECURITY:
|
||||
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
|
||||
chan->chan_type != L2CAP_CHAN_FIXED &&
|
||||
chan->chan_type != L2CAP_CHAN_RAW) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
@@ -560,11 +573,6 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
|
||||
case BT_SNDMTU:
|
||||
if (!enable_lecoc) {
|
||||
err = -EPROTONOSUPPORT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!bdaddr_type_is_le(chan->src_type)) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
@@ -580,11 +588,6 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
|
||||
case BT_RCVMTU:
|
||||
if (!enable_lecoc) {
|
||||
err = -EPROTONOSUPPORT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!bdaddr_type_is_le(chan->src_type)) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
@@ -699,6 +702,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
|
||||
break;
|
||||
}
|
||||
|
||||
if (opt & L2CAP_LM_FIPS) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (opt & L2CAP_LM_AUTH)
|
||||
chan->sec_level = BT_SECURITY_LOW;
|
||||
if (opt & L2CAP_LM_ENCRYPT)
|
||||
@@ -750,6 +758,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
switch (optname) {
|
||||
case BT_SECURITY:
|
||||
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
|
||||
chan->chan_type != L2CAP_CHAN_FIXED &&
|
||||
chan->chan_type != L2CAP_CHAN_RAW) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
@@ -895,11 +904,6 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
|
||||
case BT_SNDMTU:
|
||||
if (!enable_lecoc) {
|
||||
err = -EPROTONOSUPPORT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!bdaddr_type_is_le(chan->src_type)) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
@@ -912,11 +916,6 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
|
||||
case BT_RCVMTU:
|
||||
if (!enable_lecoc) {
|
||||
err = -EPROTONOSUPPORT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!bdaddr_type_is_le(chan->src_type)) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
@@ -1449,6 +1448,11 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
|
||||
chan->tx_credits = pchan->tx_credits;
|
||||
chan->rx_credits = pchan->rx_credits;
|
||||
|
||||
if (chan->chan_type == L2CAP_CHAN_FIXED) {
|
||||
chan->scid = pchan->scid;
|
||||
chan->dcid = pchan->scid;
|
||||
}
|
||||
|
||||
security_sk_clone(parent, sk);
|
||||
} else {
|
||||
switch (sk->sk_type) {
|
||||
@@ -1614,6 +1618,3 @@ void l2cap_cleanup_sockets(void)
|
||||
bt_sock_unregister(BTPROTO_L2CAP);
|
||||
proto_unregister(&l2cap_proto);
|
||||
}
|
||||
|
||||
module_param(enable_lecoc, bool, 0644);
|
||||
MODULE_PARM_DESC(enable_lecoc, "Enable support for LE CoC");
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -216,6 +216,7 @@ static int rfcomm_check_security(struct rfcomm_dlc *d)
|
||||
|
||||
switch (d->sec_level) {
|
||||
case BT_SECURITY_HIGH:
|
||||
case BT_SECURITY_FIPS:
|
||||
auth_type = HCI_AT_GENERAL_BONDING_MITM;
|
||||
break;
|
||||
case BT_SECURITY_MEDIUM:
|
||||
@@ -359,6 +360,11 @@ static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int rfcomm_check_channel(u8 channel)
|
||||
{
|
||||
return channel < 1 || channel > 30;
|
||||
}
|
||||
|
||||
static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
|
||||
{
|
||||
struct rfcomm_session *s;
|
||||
@@ -368,7 +374,7 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
|
||||
BT_DBG("dlc %p state %ld %pMR -> %pMR channel %d",
|
||||
d, d->state, src, dst, channel);
|
||||
|
||||
if (channel < 1 || channel > 30)
|
||||
if (rfcomm_check_channel(channel))
|
||||
return -EINVAL;
|
||||
|
||||
if (d->state != BT_OPEN && d->state != BT_CLOSED)
|
||||
@@ -425,6 +431,20 @@ int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 chann
|
||||
return r;
|
||||
}
|
||||
|
||||
static void __rfcomm_dlc_disconn(struct rfcomm_dlc *d)
|
||||
{
|
||||
struct rfcomm_session *s = d->session;
|
||||
|
||||
d->state = BT_DISCONN;
|
||||
if (skb_queue_empty(&d->tx_queue)) {
|
||||
rfcomm_send_disc(s, d->dlci);
|
||||
rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT);
|
||||
} else {
|
||||
rfcomm_queue_disc(d);
|
||||
rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2);
|
||||
}
|
||||
}
|
||||
|
||||
static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
|
||||
{
|
||||
struct rfcomm_session *s = d->session;
|
||||
@@ -437,32 +457,29 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
|
||||
switch (d->state) {
|
||||
case BT_CONNECT:
|
||||
case BT_CONFIG:
|
||||
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
|
||||
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
|
||||
rfcomm_schedule();
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
|
||||
case BT_CONNECTED:
|
||||
d->state = BT_DISCONN;
|
||||
if (skb_queue_empty(&d->tx_queue)) {
|
||||
rfcomm_send_disc(s, d->dlci);
|
||||
rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT);
|
||||
} else {
|
||||
rfcomm_queue_disc(d);
|
||||
rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2);
|
||||
}
|
||||
break;
|
||||
|
||||
case BT_OPEN:
|
||||
case BT_CONNECT2:
|
||||
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
|
||||
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
|
||||
rfcomm_schedule();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch (d->state) {
|
||||
case BT_CONNECT:
|
||||
case BT_CONNECTED:
|
||||
__rfcomm_dlc_disconn(d);
|
||||
break;
|
||||
|
||||
case BT_CONFIG:
|
||||
if (s->state != BT_BOUND) {
|
||||
__rfcomm_dlc_disconn(d);
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
/* if closing a dlc in a session that hasn't been started,
|
||||
* just close and unlink the dlc
|
||||
*/
|
||||
|
||||
default:
|
||||
rfcomm_dlc_clear_timer(d);
|
||||
@@ -513,6 +530,25 @@ no_session:
|
||||
return r;
|
||||
}
|
||||
|
||||
struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel)
|
||||
{
|
||||
struct rfcomm_session *s;
|
||||
struct rfcomm_dlc *dlc = NULL;
|
||||
u8 dlci;
|
||||
|
||||
if (rfcomm_check_channel(channel))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
rfcomm_lock();
|
||||
s = rfcomm_session_get(src, dst);
|
||||
if (s) {
|
||||
dlci = __dlci(!s->initiator, channel);
|
||||
dlc = rfcomm_dlc_get(s, dlci);
|
||||
}
|
||||
rfcomm_unlock();
|
||||
return dlc;
|
||||
}
|
||||
|
||||
int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
|
||||
{
|
||||
int len = skb->len;
|
||||
@@ -533,6 +569,20 @@ int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
|
||||
return len;
|
||||
}
|
||||
|
||||
void rfcomm_dlc_send_noerror(struct rfcomm_dlc *d, struct sk_buff *skb)
|
||||
{
|
||||
int len = skb->len;
|
||||
|
||||
BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
|
||||
|
||||
rfcomm_make_uih(skb, d->addr);
|
||||
skb_queue_tail(&d->tx_queue, skb);
|
||||
|
||||
if (d->state == BT_CONNECTED &&
|
||||
!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
|
||||
rfcomm_schedule();
|
||||
}
|
||||
|
||||
void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
|
||||
{
|
||||
BT_DBG("dlc %p state %ld", d, d->state);
|
||||
@@ -718,7 +768,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
|
||||
|
||||
bacpy(&addr.l2_bdaddr, dst);
|
||||
addr.l2_family = AF_BLUETOOTH;
|
||||
addr.l2_psm = __constant_cpu_to_le16(RFCOMM_PSM);
|
||||
addr.l2_psm = cpu_to_le16(RFCOMM_PSM);
|
||||
addr.l2_cid = 0;
|
||||
addr.l2_bdaddr_type = BDADDR_BREDR;
|
||||
*err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
|
||||
@@ -1943,12 +1993,11 @@ static void rfcomm_process_sessions(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s->state == BT_LISTEN) {
|
||||
switch (s->state) {
|
||||
case BT_LISTEN:
|
||||
rfcomm_accept_connection(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (s->state) {
|
||||
case BT_BOUND:
|
||||
s = rfcomm_check_connection(s);
|
||||
break;
|
||||
@@ -1983,7 +2032,7 @@ static int rfcomm_add_listener(bdaddr_t *ba)
|
||||
/* Bind socket */
|
||||
bacpy(&addr.l2_bdaddr, ba);
|
||||
addr.l2_family = AF_BLUETOOTH;
|
||||
addr.l2_psm = __constant_cpu_to_le16(RFCOMM_PSM);
|
||||
addr.l2_psm = cpu_to_le16(RFCOMM_PSM);
|
||||
addr.l2_cid = 0;
|
||||
addr.l2_bdaddr_type = BDADDR_BREDR;
|
||||
err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
|
||||
@@ -2085,7 +2134,8 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
|
||||
set_bit(RFCOMM_SEC_PENDING, &d->flags);
|
||||
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
|
||||
continue;
|
||||
} else if (d->sec_level == BT_SECURITY_HIGH) {
|
||||
} else if (d->sec_level == BT_SECURITY_HIGH ||
|
||||
d->sec_level == BT_SECURITY_FIPS) {
|
||||
set_bit(RFCOMM_ENC_DROP, &d->flags);
|
||||
continue;
|
||||
}
|
||||
|
@@ -105,13 +105,18 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
|
||||
}
|
||||
|
||||
/* ---- Socket functions ---- */
|
||||
static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src)
|
||||
static struct sock *__rfcomm_get_listen_sock_by_addr(u8 channel, bdaddr_t *src)
|
||||
{
|
||||
struct sock *sk = NULL;
|
||||
|
||||
sk_for_each(sk, &rfcomm_sk_list.head) {
|
||||
if (rfcomm_pi(sk)->channel == channel &&
|
||||
!bacmp(&rfcomm_pi(sk)->src, src))
|
||||
if (rfcomm_pi(sk)->channel != channel)
|
||||
continue;
|
||||
|
||||
if (bacmp(&rfcomm_pi(sk)->src, src))
|
||||
continue;
|
||||
|
||||
if (sk->sk_state == BT_BOUND || sk->sk_state == BT_LISTEN)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -331,6 +336,7 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
|
||||
{
|
||||
struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
|
||||
struct sock *sk = sock->sk;
|
||||
int chan = sa->rc_channel;
|
||||
int err = 0;
|
||||
|
||||
BT_DBG("sk %p %pMR", sk, &sa->rc_bdaddr);
|
||||
@@ -352,12 +358,12 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
|
||||
|
||||
write_lock(&rfcomm_sk_list.lock);
|
||||
|
||||
if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
|
||||
if (chan && __rfcomm_get_listen_sock_by_addr(chan, &sa->rc_bdaddr)) {
|
||||
err = -EADDRINUSE;
|
||||
} else {
|
||||
/* Save source address */
|
||||
bacpy(&rfcomm_pi(sk)->src, &sa->rc_bdaddr);
|
||||
rfcomm_pi(sk)->channel = sa->rc_channel;
|
||||
rfcomm_pi(sk)->channel = chan;
|
||||
sk->sk_state = BT_BOUND;
|
||||
}
|
||||
|
||||
@@ -439,7 +445,7 @@ static int rfcomm_sock_listen(struct socket *sock, int backlog)
|
||||
write_lock(&rfcomm_sk_list.lock);
|
||||
|
||||
for (channel = 1; channel < 31; channel++)
|
||||
if (!__rfcomm_get_sock_by_addr(channel, src)) {
|
||||
if (!__rfcomm_get_listen_sock_by_addr(channel, src)) {
|
||||
rfcomm_pi(sk)->channel = channel;
|
||||
err = 0;
|
||||
break;
|
||||
@@ -528,6 +534,10 @@ static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *
|
||||
|
||||
BT_DBG("sock %p, sk %p", sock, sk);
|
||||
|
||||
if (peer && sk->sk_state != BT_CONNECTED &&
|
||||
sk->sk_state != BT_CONNECT && sk->sk_state != BT_CONNECT2)
|
||||
return -ENOTCONN;
|
||||
|
||||
memset(sa, 0, sizeof(*sa));
|
||||
sa->rc_family = AF_BLUETOOTH;
|
||||
sa->rc_channel = rfcomm_pi(sk)->channel;
|
||||
@@ -648,6 +658,11 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __u
|
||||
break;
|
||||
}
|
||||
|
||||
if (opt & RFCOMM_LM_FIPS) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (opt & RFCOMM_LM_AUTH)
|
||||
rfcomm_pi(sk)->sec_level = BT_SECURITY_LOW;
|
||||
if (opt & RFCOMM_LM_ENCRYPT)
|
||||
@@ -762,7 +777,11 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
|
||||
break;
|
||||
case BT_SECURITY_HIGH:
|
||||
opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
|
||||
RFCOMM_LM_SECURE;
|
||||
RFCOMM_LM_SECURE;
|
||||
break;
|
||||
case BT_SECURITY_FIPS:
|
||||
opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
|
||||
RFCOMM_LM_SECURE | RFCOMM_LM_FIPS;
|
||||
break;
|
||||
default:
|
||||
opt = 0;
|
||||
@@ -774,6 +793,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
|
||||
|
||||
if (put_user(opt, (u32 __user *) optval))
|
||||
err = -EFAULT;
|
||||
|
||||
break;
|
||||
|
||||
case RFCOMM_CONNINFO:
|
||||
|
@@ -40,6 +40,7 @@
|
||||
#define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */
|
||||
#define RFCOMM_TTY_MINOR 0
|
||||
|
||||
static DEFINE_MUTEX(rfcomm_ioctl_mutex);
|
||||
static struct tty_driver *rfcomm_tty_driver;
|
||||
|
||||
struct rfcomm_dev {
|
||||
@@ -51,6 +52,8 @@ struct rfcomm_dev {
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
unsigned long status; /* don't export to userspace */
|
||||
|
||||
bdaddr_t src;
|
||||
bdaddr_t dst;
|
||||
u8 channel;
|
||||
@@ -58,7 +61,6 @@ struct rfcomm_dev {
|
||||
uint modem_status;
|
||||
|
||||
struct rfcomm_dlc *dlc;
|
||||
wait_queue_head_t conn_wait;
|
||||
|
||||
struct device *tty_dev;
|
||||
|
||||
@@ -83,10 +85,6 @@ static void rfcomm_dev_destruct(struct tty_port *port)
|
||||
|
||||
BT_DBG("dev %p dlc %p", dev, dlc);
|
||||
|
||||
spin_lock(&rfcomm_dev_lock);
|
||||
list_del(&dev->list);
|
||||
spin_unlock(&rfcomm_dev_lock);
|
||||
|
||||
rfcomm_dlc_lock(dlc);
|
||||
/* Detach DLC if it's owned by this dev */
|
||||
if (dlc->owner == dev)
|
||||
@@ -95,7 +93,12 @@ static void rfcomm_dev_destruct(struct tty_port *port)
|
||||
|
||||
rfcomm_dlc_put(dlc);
|
||||
|
||||
tty_unregister_device(rfcomm_tty_driver, dev->id);
|
||||
if (dev->tty_dev)
|
||||
tty_unregister_device(rfcomm_tty_driver, dev->id);
|
||||
|
||||
spin_lock(&rfcomm_dev_lock);
|
||||
list_del(&dev->list);
|
||||
spin_unlock(&rfcomm_dev_lock);
|
||||
|
||||
kfree(dev);
|
||||
|
||||
@@ -104,62 +107,26 @@ static void rfcomm_dev_destruct(struct tty_port *port)
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
|
||||
{
|
||||
struct hci_dev *hdev;
|
||||
struct hci_conn *conn;
|
||||
|
||||
hdev = hci_get_route(&dev->dst, &dev->src);
|
||||
if (!hdev)
|
||||
return NULL;
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
|
||||
|
||||
hci_dev_put(hdev);
|
||||
|
||||
return conn ? &conn->dev : NULL;
|
||||
}
|
||||
|
||||
/* device-specific initialization: open the dlc */
|
||||
static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty)
|
||||
{
|
||||
struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
|
||||
DEFINE_WAIT(wait);
|
||||
int err;
|
||||
|
||||
err = rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
while (1) {
|
||||
prepare_to_wait(&dev->conn_wait, &wait, TASK_INTERRUPTIBLE);
|
||||
|
||||
if (dev->dlc->state == BT_CLOSED) {
|
||||
err = -dev->err;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dev->dlc->state == BT_CONNECTED)
|
||||
break;
|
||||
|
||||
if (signal_pending(current)) {
|
||||
err = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
tty_unlock(tty);
|
||||
schedule();
|
||||
tty_lock(tty);
|
||||
}
|
||||
finish_wait(&dev->conn_wait, &wait);
|
||||
|
||||
if (!err)
|
||||
device_move(dev->tty_dev, rfcomm_get_device(dev),
|
||||
DPM_ORDER_DEV_AFTER_PARENT);
|
||||
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* we block the open until the dlc->state becomes BT_CONNECTED */
|
||||
static int rfcomm_dev_carrier_raised(struct tty_port *port)
|
||||
{
|
||||
struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
|
||||
|
||||
return (dev->dlc->state == BT_CONNECTED);
|
||||
}
|
||||
|
||||
/* device-specific cleanup: close the dlc */
|
||||
static void rfcomm_dev_shutdown(struct tty_port *port)
|
||||
{
|
||||
@@ -176,9 +143,10 @@ static const struct tty_port_operations rfcomm_port_ops = {
|
||||
.destruct = rfcomm_dev_destruct,
|
||||
.activate = rfcomm_dev_activate,
|
||||
.shutdown = rfcomm_dev_shutdown,
|
||||
.carrier_raised = rfcomm_dev_carrier_raised,
|
||||
};
|
||||
|
||||
static struct rfcomm_dev *__rfcomm_dev_get(int id)
|
||||
static struct rfcomm_dev *__rfcomm_dev_lookup(int id)
|
||||
{
|
||||
struct rfcomm_dev *dev;
|
||||
|
||||
@@ -195,20 +163,41 @@ static struct rfcomm_dev *rfcomm_dev_get(int id)
|
||||
|
||||
spin_lock(&rfcomm_dev_lock);
|
||||
|
||||
dev = __rfcomm_dev_get(id);
|
||||
dev = __rfcomm_dev_lookup(id);
|
||||
|
||||
if (dev) {
|
||||
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
|
||||
dev = NULL;
|
||||
else
|
||||
tty_port_get(&dev->port);
|
||||
}
|
||||
if (dev && !tty_port_get(&dev->port))
|
||||
dev = NULL;
|
||||
|
||||
spin_unlock(&rfcomm_dev_lock);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void rfcomm_reparent_device(struct rfcomm_dev *dev)
|
||||
{
|
||||
struct hci_dev *hdev;
|
||||
struct hci_conn *conn;
|
||||
|
||||
hdev = hci_get_route(&dev->dst, &dev->src);
|
||||
if (!hdev)
|
||||
return;
|
||||
|
||||
/* The lookup results are unsafe to access without the
|
||||
* hci device lock (FIXME: why is this not documented?)
|
||||
*/
|
||||
hci_dev_lock(hdev);
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
|
||||
|
||||
/* Just because the acl link is in the hash table is no
|
||||
* guarantee the sysfs device has been added ...
|
||||
*/
|
||||
if (conn && device_is_registered(&conn->dev))
|
||||
device_move(dev->tty_dev, &conn->dev, DPM_ORDER_DEV_AFTER_PARENT);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
hci_dev_put(hdev);
|
||||
}
|
||||
|
||||
static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
|
||||
@@ -224,17 +213,16 @@ static ssize_t show_channel(struct device *tty_dev, struct device_attribute *att
|
||||
static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
|
||||
static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
|
||||
|
||||
static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
|
||||
static struct rfcomm_dev *__rfcomm_dev_add(struct rfcomm_dev_req *req,
|
||||
struct rfcomm_dlc *dlc)
|
||||
{
|
||||
struct rfcomm_dev *dev, *entry;
|
||||
struct list_head *head = &rfcomm_dev_list;
|
||||
int err = 0;
|
||||
|
||||
BT_DBG("id %d channel %d", req->dev_id, req->channel);
|
||||
|
||||
dev = kzalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
spin_lock(&rfcomm_dev_lock);
|
||||
|
||||
@@ -282,7 +270,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
|
||||
|
||||
tty_port_init(&dev->port);
|
||||
dev->port.ops = &rfcomm_port_ops;
|
||||
init_waitqueue_head(&dev->conn_wait);
|
||||
|
||||
skb_queue_head_init(&dev->pending);
|
||||
|
||||
@@ -318,22 +305,37 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
|
||||
holds reference to this module. */
|
||||
__module_get(THIS_MODULE);
|
||||
|
||||
spin_unlock(&rfcomm_dev_lock);
|
||||
return dev;
|
||||
|
||||
out:
|
||||
spin_unlock(&rfcomm_dev_lock);
|
||||
kfree(dev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
if (err < 0)
|
||||
goto free;
|
||||
static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
|
||||
{
|
||||
struct rfcomm_dev *dev;
|
||||
struct device *tty;
|
||||
|
||||
dev->tty_dev = tty_port_register_device(&dev->port, rfcomm_tty_driver,
|
||||
dev->id, NULL);
|
||||
if (IS_ERR(dev->tty_dev)) {
|
||||
err = PTR_ERR(dev->tty_dev);
|
||||
spin_lock(&rfcomm_dev_lock);
|
||||
list_del(&dev->list);
|
||||
spin_unlock(&rfcomm_dev_lock);
|
||||
goto free;
|
||||
BT_DBG("id %d channel %d", req->dev_id, req->channel);
|
||||
|
||||
dev = __rfcomm_dev_add(req, dlc);
|
||||
if (IS_ERR(dev)) {
|
||||
rfcomm_dlc_put(dlc);
|
||||
return PTR_ERR(dev);
|
||||
}
|
||||
|
||||
tty = tty_port_register_device(&dev->port, rfcomm_tty_driver,
|
||||
dev->id, NULL);
|
||||
if (IS_ERR(tty)) {
|
||||
tty_port_put(&dev->port);
|
||||
return PTR_ERR(tty);
|
||||
}
|
||||
|
||||
dev->tty_dev = tty;
|
||||
rfcomm_reparent_device(dev);
|
||||
dev_set_drvdata(dev->tty_dev, dev);
|
||||
|
||||
if (device_create_file(dev->tty_dev, &dev_attr_address) < 0)
|
||||
@@ -343,24 +345,23 @@ out:
|
||||
BT_ERR("Failed to create channel attribute");
|
||||
|
||||
return dev->id;
|
||||
|
||||
free:
|
||||
kfree(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* ---- Send buffer ---- */
|
||||
static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
|
||||
static inline unsigned int rfcomm_room(struct rfcomm_dev *dev)
|
||||
{
|
||||
/* We can't let it be zero, because we don't get a callback
|
||||
when tx_credits becomes nonzero, hence we'd never wake up */
|
||||
return dlc->mtu * (dlc->tx_credits?:1);
|
||||
struct rfcomm_dlc *dlc = dev->dlc;
|
||||
|
||||
/* Limit the outstanding number of packets not yet sent to 40 */
|
||||
int pending = 40 - atomic_read(&dev->wmem_alloc);
|
||||
|
||||
return max(0, pending) * dlc->mtu;
|
||||
}
|
||||
|
||||
static void rfcomm_wfree(struct sk_buff *skb)
|
||||
{
|
||||
struct rfcomm_dev *dev = (void *) skb->sk;
|
||||
atomic_sub(skb->truesize, &dev->wmem_alloc);
|
||||
atomic_dec(&dev->wmem_alloc);
|
||||
if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
|
||||
tty_port_tty_wakeup(&dev->port);
|
||||
tty_port_put(&dev->port);
|
||||
@@ -369,28 +370,24 @@ static void rfcomm_wfree(struct sk_buff *skb)
|
||||
static void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
|
||||
{
|
||||
tty_port_get(&dev->port);
|
||||
atomic_add(skb->truesize, &dev->wmem_alloc);
|
||||
atomic_inc(&dev->wmem_alloc);
|
||||
skb->sk = (void *) dev;
|
||||
skb->destructor = rfcomm_wfree;
|
||||
}
|
||||
|
||||
static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, gfp_t priority)
|
||||
{
|
||||
if (atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) {
|
||||
struct sk_buff *skb = alloc_skb(size, priority);
|
||||
if (skb) {
|
||||
rfcomm_set_owner_w(skb, dev);
|
||||
return skb;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
struct sk_buff *skb = alloc_skb(size, priority);
|
||||
if (skb)
|
||||
rfcomm_set_owner_w(skb, dev);
|
||||
return skb;
|
||||
}
|
||||
|
||||
/* ---- Device IOCTLs ---- */
|
||||
|
||||
#define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP))
|
||||
|
||||
static int rfcomm_create_dev(struct sock *sk, void __user *arg)
|
||||
static int __rfcomm_create_dev(struct sock *sk, void __user *arg)
|
||||
{
|
||||
struct rfcomm_dev_req req;
|
||||
struct rfcomm_dlc *dlc;
|
||||
@@ -412,16 +409,22 @@ static int rfcomm_create_dev(struct sock *sk, void __user *arg)
|
||||
dlc = rfcomm_pi(sk)->dlc;
|
||||
rfcomm_dlc_hold(dlc);
|
||||
} else {
|
||||
/* Validate the channel is unused */
|
||||
dlc = rfcomm_dlc_exists(&req.src, &req.dst, req.channel);
|
||||
if (IS_ERR(dlc))
|
||||
return PTR_ERR(dlc);
|
||||
else if (dlc) {
|
||||
rfcomm_dlc_put(dlc);
|
||||
return -EBUSY;
|
||||
}
|
||||
dlc = rfcomm_dlc_alloc(GFP_KERNEL);
|
||||
if (!dlc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
id = rfcomm_dev_add(&req, dlc);
|
||||
if (id < 0) {
|
||||
rfcomm_dlc_put(dlc);
|
||||
if (id < 0)
|
||||
return id;
|
||||
}
|
||||
|
||||
if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
|
||||
/* DLC is now used by device.
|
||||
@@ -432,7 +435,7 @@ static int rfcomm_create_dev(struct sock *sk, void __user *arg)
|
||||
return id;
|
||||
}
|
||||
|
||||
static int rfcomm_release_dev(void __user *arg)
|
||||
static int __rfcomm_release_dev(void __user *arg)
|
||||
{
|
||||
struct rfcomm_dev_req req;
|
||||
struct rfcomm_dev *dev;
|
||||
@@ -452,6 +455,12 @@ static int rfcomm_release_dev(void __user *arg)
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/* only release once */
|
||||
if (test_and_set_bit(RFCOMM_DEV_RELEASED, &dev->status)) {
|
||||
tty_port_put(&dev->port);
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
if (req.flags & (1 << RFCOMM_HANGUP_NOW))
|
||||
rfcomm_dlc_close(dev->dlc, 0);
|
||||
|
||||
@@ -462,14 +471,35 @@ static int rfcomm_release_dev(void __user *arg)
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) &&
|
||||
!test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
|
||||
if (!test_bit(RFCOMM_TTY_OWNED, &dev->status))
|
||||
tty_port_put(&dev->port);
|
||||
|
||||
tty_port_put(&dev->port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rfcomm_create_dev(struct sock *sk, void __user *arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&rfcomm_ioctl_mutex);
|
||||
ret = __rfcomm_create_dev(sk, arg);
|
||||
mutex_unlock(&rfcomm_ioctl_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rfcomm_release_dev(void __user *arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&rfcomm_ioctl_mutex);
|
||||
ret = __rfcomm_release_dev(arg);
|
||||
mutex_unlock(&rfcomm_ioctl_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rfcomm_get_dev_list(void __user *arg)
|
||||
{
|
||||
struct rfcomm_dev *dev;
|
||||
@@ -497,7 +527,7 @@ static int rfcomm_get_dev_list(void __user *arg)
|
||||
spin_lock(&rfcomm_dev_lock);
|
||||
|
||||
list_for_each_entry(dev, &rfcomm_dev_list, list) {
|
||||
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
|
||||
if (!tty_port_get(&dev->port))
|
||||
continue;
|
||||
(di + n)->id = dev->id;
|
||||
(di + n)->flags = dev->flags;
|
||||
@@ -505,6 +535,7 @@ static int rfcomm_get_dev_list(void __user *arg)
|
||||
(di + n)->channel = dev->channel;
|
||||
bacpy(&(di + n)->src, &dev->src);
|
||||
bacpy(&(di + n)->dst, &dev->dst);
|
||||
tty_port_put(&dev->port);
|
||||
if (++n >= dev_num)
|
||||
break;
|
||||
}
|
||||
@@ -601,9 +632,11 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
|
||||
BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
|
||||
|
||||
dev->err = err;
|
||||
wake_up_interruptible(&dev->conn_wait);
|
||||
if (dlc->state == BT_CONNECTED) {
|
||||
rfcomm_reparent_device(dev);
|
||||
|
||||
if (dlc->state == BT_CLOSED)
|
||||
wake_up_interruptible(&dev->port.open_wait);
|
||||
} else if (dlc->state == BT_CLOSED)
|
||||
tty_port_tty_hangup(&dev->port, false);
|
||||
}
|
||||
|
||||
@@ -703,8 +736,10 @@ static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||
* when the last process closes the tty. The behaviour is expected by
|
||||
* userspace.
|
||||
*/
|
||||
if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
|
||||
if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
|
||||
set_bit(RFCOMM_TTY_OWNED, &dev->status);
|
||||
tty_port_put(&dev->port);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -750,7 +785,7 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in
|
||||
struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
|
||||
struct rfcomm_dlc *dlc = dev->dlc;
|
||||
struct sk_buff *skb;
|
||||
int err = 0, sent = 0, size;
|
||||
int sent = 0, size;
|
||||
|
||||
BT_DBG("tty %p count %d", tty, count);
|
||||
|
||||
@@ -758,7 +793,6 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in
|
||||
size = min_t(uint, count, dlc->mtu);
|
||||
|
||||
skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_ATOMIC);
|
||||
|
||||
if (!skb)
|
||||
break;
|
||||
|
||||
@@ -766,32 +800,24 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in
|
||||
|
||||
memcpy(skb_put(skb, size), buf + sent, size);
|
||||
|
||||
err = rfcomm_dlc_send(dlc, skb);
|
||||
if (err < 0) {
|
||||
kfree_skb(skb);
|
||||
break;
|
||||
}
|
||||
rfcomm_dlc_send_noerror(dlc, skb);
|
||||
|
||||
sent += size;
|
||||
count -= size;
|
||||
}
|
||||
|
||||
return sent ? sent : err;
|
||||
return sent;
|
||||
}
|
||||
|
||||
static int rfcomm_tty_write_room(struct tty_struct *tty)
|
||||
{
|
||||
struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
|
||||
int room;
|
||||
int room = 0;
|
||||
|
||||
BT_DBG("tty %p", tty);
|
||||
if (dev && dev->dlc)
|
||||
room = rfcomm_room(dev);
|
||||
|
||||
if (!dev || !dev->dlc)
|
||||
return 0;
|
||||
|
||||
room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc);
|
||||
if (room < 0)
|
||||
room = 0;
|
||||
BT_DBG("tty %p room %d", tty, room);
|
||||
|
||||
return room;
|
||||
}
|
||||
@@ -1125,7 +1151,7 @@ int __init rfcomm_init_ttys(void)
|
||||
rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
|
||||
rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
|
||||
rfcomm_tty_driver->init_termios = tty_std_termios;
|
||||
rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
|
||||
rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
|
||||
rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
|
||||
tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
|
||||
|
||||
|
@@ -676,20 +676,20 @@ static void sco_conn_defer_accept(struct hci_conn *conn, u16 setting)
|
||||
bacpy(&cp.bdaddr, &conn->dst);
|
||||
cp.pkt_type = cpu_to_le16(conn->pkt_type);
|
||||
|
||||
cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
||||
cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
||||
cp.tx_bandwidth = cpu_to_le32(0x00001f40);
|
||||
cp.rx_bandwidth = cpu_to_le32(0x00001f40);
|
||||
cp.content_format = cpu_to_le16(setting);
|
||||
|
||||
switch (setting & SCO_AIRMODE_MASK) {
|
||||
case SCO_AIRMODE_TRANSP:
|
||||
if (conn->pkt_type & ESCO_2EV3)
|
||||
cp.max_latency = __constant_cpu_to_le16(0x0008);
|
||||
cp.max_latency = cpu_to_le16(0x0008);
|
||||
else
|
||||
cp.max_latency = __constant_cpu_to_le16(0x000D);
|
||||
cp.max_latency = cpu_to_le16(0x000D);
|
||||
cp.retrans_effort = 0x02;
|
||||
break;
|
||||
case SCO_AIRMODE_CVSD:
|
||||
cp.max_latency = __constant_cpu_to_le16(0xffff);
|
||||
cp.max_latency = cpu_to_le16(0xffff);
|
||||
cp.retrans_effort = 0xff;
|
||||
break;
|
||||
}
|
||||
|
@@ -35,14 +35,14 @@
|
||||
|
||||
#define AUTH_REQ_MASK 0x07
|
||||
|
||||
static inline void swap128(u8 src[16], u8 dst[16])
|
||||
static inline void swap128(const u8 src[16], u8 dst[16])
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 16; i++)
|
||||
dst[15 - i] = src[i];
|
||||
}
|
||||
|
||||
static inline void swap56(u8 src[7], u8 dst[7])
|
||||
static inline void swap56(const u8 src[7], u8 dst[7])
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 7; i++)
|
||||
@@ -53,6 +53,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
|
||||
{
|
||||
struct blkcipher_desc desc;
|
||||
struct scatterlist sg;
|
||||
uint8_t tmp[16], data[16];
|
||||
int err;
|
||||
|
||||
if (tfm == NULL) {
|
||||
@@ -63,21 +64,89 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
|
||||
desc.tfm = tfm;
|
||||
desc.flags = 0;
|
||||
|
||||
err = crypto_blkcipher_setkey(tfm, k, 16);
|
||||
/* The most significant octet of key corresponds to k[0] */
|
||||
swap128(k, tmp);
|
||||
|
||||
err = crypto_blkcipher_setkey(tfm, tmp, 16);
|
||||
if (err) {
|
||||
BT_ERR("cipher setkey failed: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
sg_init_one(&sg, r, 16);
|
||||
/* Most significant octet of plaintextData corresponds to data[0] */
|
||||
swap128(r, data);
|
||||
|
||||
sg_init_one(&sg, data, 16);
|
||||
|
||||
err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16);
|
||||
if (err)
|
||||
BT_ERR("Encrypt data error %d", err);
|
||||
|
||||
/* Most significant octet of encryptedData corresponds to data[0] */
|
||||
swap128(data, r);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3])
|
||||
{
|
||||
u8 _res[16];
|
||||
int err;
|
||||
|
||||
/* r' = padding || r */
|
||||
memcpy(_res, r, 3);
|
||||
memset(_res + 3, 0, 13);
|
||||
|
||||
err = smp_e(tfm, irk, _res);
|
||||
if (err) {
|
||||
BT_ERR("Encrypt error");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The output of the random address function ah is:
|
||||
* ah(h, r) = e(k, r') mod 2^24
|
||||
* The output of the security function e is then truncated to 24 bits
|
||||
* by taking the least significant 24 bits of the output of e as the
|
||||
* result of ah.
|
||||
*/
|
||||
memcpy(res, _res, 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
|
||||
bdaddr_t *bdaddr)
|
||||
{
|
||||
u8 hash[3];
|
||||
int err;
|
||||
|
||||
BT_DBG("RPA %pMR IRK %*phN", bdaddr, 16, irk);
|
||||
|
||||
err = smp_ah(tfm, irk, &bdaddr->b[3], hash);
|
||||
if (err)
|
||||
return false;
|
||||
|
||||
return !memcmp(bdaddr->b, hash, 3);
|
||||
}
|
||||
|
||||
int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa)
|
||||
{
|
||||
int err;
|
||||
|
||||
get_random_bytes(&rpa->b[3], 3);
|
||||
|
||||
rpa->b[5] &= 0x3f; /* Clear two most significant bits */
|
||||
rpa->b[5] |= 0x40; /* Set second most significant bit */
|
||||
|
||||
err = smp_ah(tfm, irk, &rpa->b[3], rpa->b);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
BT_DBG("RPA %pMR", rpa);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
|
||||
u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia,
|
||||
u8 _rat, bdaddr_t *ra, u8 res[16])
|
||||
@@ -88,16 +157,15 @@ static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
|
||||
memset(p1, 0, 16);
|
||||
|
||||
/* p1 = pres || preq || _rat || _iat */
|
||||
swap56(pres, p1);
|
||||
swap56(preq, p1 + 7);
|
||||
p1[14] = _rat;
|
||||
p1[15] = _iat;
|
||||
|
||||
memset(p2, 0, 16);
|
||||
p1[0] = _iat;
|
||||
p1[1] = _rat;
|
||||
memcpy(p1 + 2, preq, 7);
|
||||
memcpy(p1 + 9, pres, 7);
|
||||
|
||||
/* p2 = padding || ia || ra */
|
||||
baswap((bdaddr_t *) (p2 + 4), ia);
|
||||
baswap((bdaddr_t *) (p2 + 10), ra);
|
||||
memcpy(p2, ra, 6);
|
||||
memcpy(p2 + 6, ia, 6);
|
||||
memset(p2 + 12, 0, 4);
|
||||
|
||||
/* res = r XOR p1 */
|
||||
u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
|
||||
@@ -126,8 +194,8 @@ static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16], u8 r1[16],
|
||||
int err;
|
||||
|
||||
/* Just least significant octets from r1 and r2 are considered */
|
||||
memcpy(_r, r1 + 8, 8);
|
||||
memcpy(_r + 8, r2 + 8, 8);
|
||||
memcpy(_r, r2, 8);
|
||||
memcpy(_r + 8, r1, 8);
|
||||
|
||||
err = smp_e(tfm, k, _r);
|
||||
if (err)
|
||||
@@ -154,7 +222,7 @@ static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
|
||||
|
||||
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
|
||||
lh->len = cpu_to_le16(sizeof(code) + dlen);
|
||||
lh->cid = __constant_cpu_to_le16(L2CAP_CID_SMP);
|
||||
lh->cid = cpu_to_le16(L2CAP_CID_SMP);
|
||||
|
||||
memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
|
||||
|
||||
@@ -203,31 +271,45 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
|
||||
struct smp_cmd_pairing *req,
|
||||
struct smp_cmd_pairing *rsp, __u8 authreq)
|
||||
{
|
||||
u8 dist_keys = 0;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
u8 local_dist = 0, remote_dist = 0;
|
||||
|
||||
if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) {
|
||||
dist_keys = SMP_DIST_ENC_KEY;
|
||||
local_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN;
|
||||
remote_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN;
|
||||
authreq |= SMP_AUTH_BONDING;
|
||||
} else {
|
||||
authreq &= ~SMP_AUTH_BONDING;
|
||||
}
|
||||
|
||||
if (test_bit(HCI_RPA_RESOLVING, &hdev->dev_flags))
|
||||
remote_dist |= SMP_DIST_ID_KEY;
|
||||
|
||||
if (test_bit(HCI_PRIVACY, &hdev->dev_flags))
|
||||
local_dist |= SMP_DIST_ID_KEY;
|
||||
|
||||
if (rsp == NULL) {
|
||||
req->io_capability = conn->hcon->io_capability;
|
||||
req->oob_flag = SMP_OOB_NOT_PRESENT;
|
||||
req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
|
||||
req->init_key_dist = 0;
|
||||
req->resp_key_dist = dist_keys;
|
||||
req->init_key_dist = local_dist;
|
||||
req->resp_key_dist = remote_dist;
|
||||
req->auth_req = (authreq & AUTH_REQ_MASK);
|
||||
|
||||
smp->remote_key_dist = remote_dist;
|
||||
return;
|
||||
}
|
||||
|
||||
rsp->io_capability = conn->hcon->io_capability;
|
||||
rsp->oob_flag = SMP_OOB_NOT_PRESENT;
|
||||
rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
|
||||
rsp->init_key_dist = 0;
|
||||
rsp->resp_key_dist = req->resp_key_dist & dist_keys;
|
||||
rsp->init_key_dist = req->init_key_dist & remote_dist;
|
||||
rsp->resp_key_dist = req->resp_key_dist & local_dist;
|
||||
rsp->auth_req = (authreq & AUTH_REQ_MASK);
|
||||
|
||||
smp->remote_key_dist = rsp->init_key_dist;
|
||||
}
|
||||
|
||||
static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
|
||||
@@ -305,6 +387,11 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
||||
if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
|
||||
method = JUST_WORKS;
|
||||
|
||||
/* Don't confirm locally initiated pairing attempts */
|
||||
if (method == JUST_CFM && test_bit(SMP_FLAG_INITIATOR,
|
||||
&smp->smp_flags))
|
||||
method = JUST_WORKS;
|
||||
|
||||
/* If Just Works, Continue with Zero TK */
|
||||
if (method == JUST_WORKS) {
|
||||
set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
|
||||
@@ -325,16 +412,14 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
||||
method = REQ_PASSKEY;
|
||||
}
|
||||
|
||||
/* Generate random passkey. Not valid until confirmed. */
|
||||
/* Generate random passkey. */
|
||||
if (method == CFM_PASSKEY) {
|
||||
u8 key[16];
|
||||
|
||||
memset(key, 0, sizeof(key));
|
||||
memset(smp->tk, 0, sizeof(smp->tk));
|
||||
get_random_bytes(&passkey, sizeof(passkey));
|
||||
passkey %= 1000000;
|
||||
put_unaligned_le32(passkey, key);
|
||||
swap128(key, smp->tk);
|
||||
put_unaligned_le32(passkey, smp->tk);
|
||||
BT_DBG("PassKey: %d", passkey);
|
||||
set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
|
||||
}
|
||||
|
||||
hci_dev_lock(hcon->hdev);
|
||||
@@ -342,10 +427,14 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
||||
if (method == REQ_PASSKEY)
|
||||
ret = mgmt_user_passkey_request(hcon->hdev, &hcon->dst,
|
||||
hcon->type, hcon->dst_type);
|
||||
else
|
||||
else if (method == JUST_CFM)
|
||||
ret = mgmt_user_confirm_request(hcon->hdev, &hcon->dst,
|
||||
hcon->type, hcon->dst_type,
|
||||
cpu_to_le32(passkey), 0);
|
||||
passkey, 1);
|
||||
else
|
||||
ret = mgmt_user_passkey_notify(hcon->hdev, &hcon->dst,
|
||||
hcon->type, hcon->dst_type,
|
||||
passkey, 0);
|
||||
|
||||
hci_dev_unlock(hcon->hdev);
|
||||
|
||||
@@ -356,29 +445,24 @@ static void confirm_work(struct work_struct *work)
|
||||
{
|
||||
struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
|
||||
struct l2cap_conn *conn = smp->conn;
|
||||
struct crypto_blkcipher *tfm;
|
||||
struct hci_dev *hdev = conn->hcon->hdev;
|
||||
struct crypto_blkcipher *tfm = hdev->tfm_aes;
|
||||
struct smp_cmd_pairing_confirm cp;
|
||||
int ret;
|
||||
u8 res[16], reason;
|
||||
u8 reason;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm)) {
|
||||
reason = SMP_UNSPECIFIED;
|
||||
goto error;
|
||||
}
|
||||
/* Prevent mutual access to hdev->tfm_aes */
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
smp->tfm = tfm;
|
||||
ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
|
||||
conn->hcon->init_addr_type, &conn->hcon->init_addr,
|
||||
conn->hcon->resp_addr_type, &conn->hcon->resp_addr,
|
||||
cp.confirm_val);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
if (conn->hcon->out)
|
||||
ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
|
||||
conn->hcon->src_type, &conn->hcon->src,
|
||||
conn->hcon->dst_type, &conn->hcon->dst, res);
|
||||
else
|
||||
ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
|
||||
conn->hcon->dst_type, &conn->hcon->dst,
|
||||
conn->hcon->src_type, &conn->hcon->src, res);
|
||||
if (ret) {
|
||||
reason = SMP_UNSPECIFIED;
|
||||
goto error;
|
||||
@@ -386,7 +470,6 @@ static void confirm_work(struct work_struct *work)
|
||||
|
||||
clear_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
|
||||
|
||||
swap128(res, cp.confirm_val);
|
||||
smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
|
||||
|
||||
return;
|
||||
@@ -400,8 +483,9 @@ static void random_work(struct work_struct *work)
|
||||
struct smp_chan *smp = container_of(work, struct smp_chan, random);
|
||||
struct l2cap_conn *conn = smp->conn;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct crypto_blkcipher *tfm = smp->tfm;
|
||||
u8 reason, confirm[16], res[16], key[16];
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
struct crypto_blkcipher *tfm = hdev->tfm_aes;
|
||||
u8 reason, confirm[16];
|
||||
int ret;
|
||||
|
||||
if (IS_ERR_OR_NULL(tfm)) {
|
||||
@@ -411,21 +495,20 @@ static void random_work(struct work_struct *work)
|
||||
|
||||
BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
|
||||
|
||||
if (hcon->out)
|
||||
ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
|
||||
hcon->src_type, &hcon->src,
|
||||
hcon->dst_type, &hcon->dst, res);
|
||||
else
|
||||
ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
|
||||
hcon->dst_type, &hcon->dst,
|
||||
hcon->src_type, &hcon->src, res);
|
||||
/* Prevent mutual access to hdev->tfm_aes */
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
|
||||
hcon->init_addr_type, &hcon->init_addr,
|
||||
hcon->resp_addr_type, &hcon->resp_addr, confirm);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
if (ret) {
|
||||
reason = SMP_UNSPECIFIED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
swap128(res, confirm);
|
||||
|
||||
if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) {
|
||||
BT_ERR("Pairing failed (confirmation values mismatch)");
|
||||
reason = SMP_CONFIRM_FAILED;
|
||||
@@ -433,14 +516,11 @@ static void random_work(struct work_struct *work)
|
||||
}
|
||||
|
||||
if (hcon->out) {
|
||||
u8 stk[16], rand[8];
|
||||
__le16 ediv;
|
||||
u8 stk[16];
|
||||
__le64 rand = 0;
|
||||
__le16 ediv = 0;
|
||||
|
||||
memset(rand, 0, sizeof(rand));
|
||||
ediv = 0;
|
||||
|
||||
smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key);
|
||||
swap128(key, stk);
|
||||
smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, stk);
|
||||
|
||||
memset(stk + smp->enc_key_size, 0,
|
||||
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
|
||||
@@ -453,23 +533,20 @@ static void random_work(struct work_struct *work)
|
||||
hci_le_start_enc(hcon, ediv, rand, stk);
|
||||
hcon->enc_key_size = smp->enc_key_size;
|
||||
} else {
|
||||
u8 stk[16], r[16], rand[8];
|
||||
__le16 ediv;
|
||||
u8 stk[16];
|
||||
__le64 rand = 0;
|
||||
__le16 ediv = 0;
|
||||
|
||||
memset(rand, 0, sizeof(rand));
|
||||
ediv = 0;
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
|
||||
smp->prnd);
|
||||
|
||||
swap128(smp->prnd, r);
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
|
||||
|
||||
smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key);
|
||||
swap128(key, stk);
|
||||
smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, stk);
|
||||
|
||||
memset(stk + smp->enc_key_size, 0,
|
||||
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
|
||||
|
||||
hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
|
||||
HCI_SMP_STK_SLAVE, 0, 0, stk, smp->enc_key_size,
|
||||
HCI_SMP_STK_SLAVE, 0, stk, smp->enc_key_size,
|
||||
ediv, rand);
|
||||
}
|
||||
|
||||
@@ -502,11 +579,33 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
|
||||
void smp_chan_destroy(struct l2cap_conn *conn)
|
||||
{
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
bool complete;
|
||||
|
||||
BUG_ON(!smp);
|
||||
|
||||
if (smp->tfm)
|
||||
crypto_free_blkcipher(smp->tfm);
|
||||
complete = test_bit(SMP_FLAG_COMPLETE, &smp->smp_flags);
|
||||
mgmt_smp_complete(conn->hcon, complete);
|
||||
|
||||
kfree(smp->csrk);
|
||||
kfree(smp->slave_csrk);
|
||||
|
||||
/* If pairing failed clean up any keys we might have */
|
||||
if (!complete) {
|
||||
if (smp->ltk) {
|
||||
list_del(&smp->ltk->list);
|
||||
kfree(smp->ltk);
|
||||
}
|
||||
|
||||
if (smp->slave_ltk) {
|
||||
list_del(&smp->slave_ltk->list);
|
||||
kfree(smp->slave_ltk);
|
||||
}
|
||||
|
||||
if (smp->remote_irk) {
|
||||
list_del(&smp->remote_irk->list);
|
||||
kfree(smp->remote_irk);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(smp);
|
||||
conn->smp_chan = NULL;
|
||||
@@ -519,7 +618,6 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
|
||||
struct l2cap_conn *conn = hcon->smp_conn;
|
||||
struct smp_chan *smp;
|
||||
u32 value;
|
||||
u8 key[16];
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
@@ -531,10 +629,9 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
|
||||
switch (mgmt_op) {
|
||||
case MGMT_OP_USER_PASSKEY_REPLY:
|
||||
value = le32_to_cpu(passkey);
|
||||
memset(key, 0, sizeof(key));
|
||||
memset(smp->tk, 0, sizeof(smp->tk));
|
||||
BT_DBG("PassKey: %d", value);
|
||||
put_unaligned_le32(value, key);
|
||||
swap128(key, smp->tk);
|
||||
put_unaligned_le32(value, smp->tk);
|
||||
/* Fall Through */
|
||||
case MGMT_OP_USER_CONFIRM_REPLY:
|
||||
set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
|
||||
@@ -565,6 +662,9 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(*req))
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
if (conn->hcon->link_mode & HCI_LM_MASTER)
|
||||
return SMP_CMD_NOTSUPP;
|
||||
|
||||
@@ -604,6 +704,8 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
if (ret)
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
clear_bit(SMP_FLAG_INITIATOR, &smp->smp_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -617,6 +719,9 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(*rsp))
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
if (!(conn->hcon->link_mode & HCI_LM_MASTER))
|
||||
return SMP_CMD_NOTSUPP;
|
||||
|
||||
@@ -633,6 +738,11 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
smp->prsp[0] = SMP_CMD_PAIRING_RSP;
|
||||
memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
|
||||
|
||||
/* Update remote key distribution in case the remote cleared
|
||||
* some bits that we had enabled in our request.
|
||||
*/
|
||||
smp->remote_key_dist &= rsp->resp_key_dist;
|
||||
|
||||
if ((req->auth_req & SMP_AUTH_BONDING) &&
|
||||
(rsp->auth_req & SMP_AUTH_BONDING))
|
||||
auth = SMP_AUTH_BONDING;
|
||||
@@ -646,10 +756,8 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
|
||||
|
||||
/* Can't compose response until we have been confirmed */
|
||||
if (!test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags))
|
||||
return 0;
|
||||
|
||||
queue_work(hdev->workqueue, &smp->confirm);
|
||||
if (test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags))
|
||||
queue_work(hdev->workqueue, &smp->confirm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -661,20 +769,19 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
|
||||
BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
|
||||
|
||||
if (skb->len < sizeof(smp->pcnf))
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
|
||||
skb_pull(skb, sizeof(smp->pcnf));
|
||||
|
||||
if (conn->hcon->out) {
|
||||
u8 random[16];
|
||||
|
||||
swap128(smp->prnd, random);
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
|
||||
random);
|
||||
} else if (test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags)) {
|
||||
if (conn->hcon->out)
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
|
||||
smp->prnd);
|
||||
else if (test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags))
|
||||
queue_work(hdev->workqueue, &smp->confirm);
|
||||
} else {
|
||||
else
|
||||
set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -686,7 +793,10 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
swap128(skb->data, smp->rrnd);
|
||||
if (skb->len < sizeof(smp->rrnd))
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
memcpy(smp->rrnd, skb->data, sizeof(smp->rrnd));
|
||||
skb_pull(skb, sizeof(smp->rrnd));
|
||||
|
||||
queue_work(hdev->workqueue, &smp->random);
|
||||
@@ -699,7 +809,8 @@ static u8 smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)
|
||||
struct smp_ltk *key;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
|
||||
key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type);
|
||||
key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type,
|
||||
hcon->out);
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
@@ -724,6 +835,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(*rp))
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
if (!(conn->hcon->link_mode & HCI_LM_MASTER))
|
||||
return SMP_CMD_NOTSUPP;
|
||||
|
||||
@@ -747,6 +861,8 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
|
||||
|
||||
clear_bit(SMP_FLAG_INITIATOR, &smp->smp_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -764,11 +880,15 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level)
|
||||
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
||||
{
|
||||
struct l2cap_conn *conn = hcon->l2cap_data;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct smp_chan *smp;
|
||||
__u8 authreq;
|
||||
|
||||
BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
|
||||
|
||||
/* This may be NULL if there's an unexpected disconnection */
|
||||
if (!conn)
|
||||
return 1;
|
||||
|
||||
if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags))
|
||||
return 1;
|
||||
|
||||
@@ -788,6 +908,12 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
||||
|
||||
authreq = seclevel_to_authreq(sec_level);
|
||||
|
||||
/* hcon->auth_type is set by pair_device in mgmt.c. If the MITM
|
||||
* flag is set we should also set it for the SMP request.
|
||||
*/
|
||||
if ((hcon->auth_type & 0x01))
|
||||
authreq |= SMP_AUTH_MITM;
|
||||
|
||||
if (hcon->link_mode & HCI_LM_MASTER) {
|
||||
struct smp_cmd_pairing cp;
|
||||
|
||||
@@ -802,6 +928,8 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
||||
smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
set_bit(SMP_FLAG_INITIATOR, &smp->smp_flags);
|
||||
|
||||
done:
|
||||
hcon->pending_sec_level = sec_level;
|
||||
|
||||
@@ -813,6 +941,15 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
struct smp_cmd_encrypt_info *rp = (void *) skb->data;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(*rp))
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
/* Ignore this PDU if it wasn't requested */
|
||||
if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY))
|
||||
return 0;
|
||||
|
||||
skb_pull(skb, sizeof(*rp));
|
||||
|
||||
memcpy(smp->tk, rp->ltk, sizeof(smp->tk));
|
||||
@@ -826,16 +963,138 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct hci_dev *hdev = conn->hcon->hdev;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct smp_ltk *ltk;
|
||||
u8 authenticated;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(*rp))
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
/* Ignore this PDU if it wasn't requested */
|
||||
if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY))
|
||||
return 0;
|
||||
|
||||
/* Mark the information as received */
|
||||
smp->remote_key_dist &= ~SMP_DIST_ENC_KEY;
|
||||
|
||||
skb_pull(skb, sizeof(*rp));
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
authenticated = (hcon->sec_level == BT_SECURITY_HIGH);
|
||||
hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, 1,
|
||||
authenticated, smp->tk, smp->enc_key_size,
|
||||
rp->ediv, rp->rand);
|
||||
smp_distribute_keys(conn, 1);
|
||||
ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK,
|
||||
authenticated, smp->tk, smp->enc_key_size,
|
||||
rp->ediv, rp->rand);
|
||||
smp->ltk = ltk;
|
||||
if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
|
||||
smp_distribute_keys(conn);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
{
|
||||
struct smp_cmd_ident_info *info = (void *) skb->data;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
if (skb->len < sizeof(*info))
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
/* Ignore this PDU if it wasn't requested */
|
||||
if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
|
||||
return 0;
|
||||
|
||||
skb_pull(skb, sizeof(*info));
|
||||
|
||||
memcpy(smp->irk, info->irk, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct smp_cmd_ident_addr_info *info = (void *) skb->data;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
bdaddr_t rpa;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
if (skb->len < sizeof(*info))
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
/* Ignore this PDU if it wasn't requested */
|
||||
if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
|
||||
return 0;
|
||||
|
||||
/* Mark the information as received */
|
||||
smp->remote_key_dist &= ~SMP_DIST_ID_KEY;
|
||||
|
||||
skb_pull(skb, sizeof(*info));
|
||||
|
||||
/* Strictly speaking the Core Specification (4.1) allows sending
|
||||
* an empty address which would force us to rely on just the IRK
|
||||
* as "identity information". However, since such
|
||||
* implementations are not known of and in order to not over
|
||||
* complicate our implementation, simply pretend that we never
|
||||
* received an IRK for such a device.
|
||||
*/
|
||||
if (!bacmp(&info->bdaddr, BDADDR_ANY)) {
|
||||
BT_ERR("Ignoring IRK with no identity address");
|
||||
smp_distribute_keys(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bacpy(&smp->id_addr, &info->bdaddr);
|
||||
smp->id_addr_type = info->addr_type;
|
||||
|
||||
if (hci_bdaddr_is_rpa(&hcon->dst, hcon->dst_type))
|
||||
bacpy(&rpa, &hcon->dst);
|
||||
else
|
||||
bacpy(&rpa, BDADDR_ANY);
|
||||
|
||||
smp->remote_irk = hci_add_irk(conn->hcon->hdev, &smp->id_addr,
|
||||
smp->id_addr_type, smp->irk, &rpa);
|
||||
|
||||
smp_distribute_keys(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
{
|
||||
struct smp_cmd_sign_info *rp = (void *) skb->data;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct hci_dev *hdev = conn->hcon->hdev;
|
||||
struct smp_csrk *csrk;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(*rp))
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
/* Ignore this PDU if it wasn't requested */
|
||||
if (!(smp->remote_key_dist & SMP_DIST_SIGN))
|
||||
return 0;
|
||||
|
||||
/* Mark the information as received */
|
||||
smp->remote_key_dist &= ~SMP_DIST_SIGN;
|
||||
|
||||
skb_pull(skb, sizeof(*rp));
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
csrk = kzalloc(sizeof(*csrk), GFP_KERNEL);
|
||||
if (csrk) {
|
||||
csrk->master = 0x01;
|
||||
memcpy(csrk->val, rp->csrk, sizeof(csrk->val));
|
||||
}
|
||||
smp->csrk = csrk;
|
||||
if (!(smp->remote_key_dist & SMP_DIST_SIGN))
|
||||
smp_distribute_keys(conn);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return 0;
|
||||
@@ -915,10 +1174,15 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
break;
|
||||
|
||||
case SMP_CMD_IDENT_INFO:
|
||||
reason = smp_cmd_ident_info(conn, skb);
|
||||
break;
|
||||
|
||||
case SMP_CMD_IDENT_ADDR_INFO:
|
||||
reason = smp_cmd_ident_addr_info(conn, skb);
|
||||
break;
|
||||
|
||||
case SMP_CMD_SIGN_INFO:
|
||||
/* Just ignored */
|
||||
reason = 0;
|
||||
reason = smp_cmd_sign_info(conn, skb);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -937,26 +1201,78 @@ done:
|
||||
return err;
|
||||
}
|
||||
|
||||
int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
|
||||
static void smp_notify_keys(struct l2cap_conn *conn)
|
||||
{
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
struct smp_cmd_pairing *req = (void *) &smp->preq[1];
|
||||
struct smp_cmd_pairing *rsp = (void *) &smp->prsp[1];
|
||||
bool persistent;
|
||||
|
||||
if (smp->remote_irk) {
|
||||
mgmt_new_irk(hdev, smp->remote_irk);
|
||||
/* Now that user space can be considered to know the
|
||||
* identity address track the connection based on it
|
||||
* from now on.
|
||||
*/
|
||||
bacpy(&hcon->dst, &smp->remote_irk->bdaddr);
|
||||
hcon->dst_type = smp->remote_irk->addr_type;
|
||||
l2cap_conn_update_id_addr(hcon);
|
||||
}
|
||||
|
||||
/* The LTKs and CSRKs should be persistent only if both sides
|
||||
* had the bonding bit set in their authentication requests.
|
||||
*/
|
||||
persistent = !!((req->auth_req & rsp->auth_req) & SMP_AUTH_BONDING);
|
||||
|
||||
if (smp->csrk) {
|
||||
smp->csrk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->csrk->bdaddr, &hcon->dst);
|
||||
mgmt_new_csrk(hdev, smp->csrk, persistent);
|
||||
}
|
||||
|
||||
if (smp->slave_csrk) {
|
||||
smp->slave_csrk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->slave_csrk->bdaddr, &hcon->dst);
|
||||
mgmt_new_csrk(hdev, smp->slave_csrk, persistent);
|
||||
}
|
||||
|
||||
if (smp->ltk) {
|
||||
smp->ltk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->ltk->bdaddr, &hcon->dst);
|
||||
mgmt_new_ltk(hdev, smp->ltk, persistent);
|
||||
}
|
||||
|
||||
if (smp->slave_ltk) {
|
||||
smp->slave_ltk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->slave_ltk->bdaddr, &hcon->dst);
|
||||
mgmt_new_ltk(hdev, smp->slave_ltk, persistent);
|
||||
}
|
||||
}
|
||||
|
||||
int smp_distribute_keys(struct l2cap_conn *conn)
|
||||
{
|
||||
struct smp_cmd_pairing *req, *rsp;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
__u8 *keydist;
|
||||
|
||||
BT_DBG("conn %p force %d", conn, force);
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
|
||||
if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
|
||||
return 0;
|
||||
|
||||
rsp = (void *) &smp->prsp[1];
|
||||
|
||||
/* The responder sends its keys first */
|
||||
if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07))
|
||||
if (hcon->out && (smp->remote_key_dist & 0x07))
|
||||
return 0;
|
||||
|
||||
req = (void *) &smp->preq[1];
|
||||
|
||||
if (conn->hcon->out) {
|
||||
if (hcon->out) {
|
||||
keydist = &rsp->init_key_dist;
|
||||
*keydist &= req->init_key_dist;
|
||||
} else {
|
||||
@@ -964,28 +1280,30 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
|
||||
*keydist &= req->resp_key_dist;
|
||||
}
|
||||
|
||||
|
||||
BT_DBG("keydist 0x%x", *keydist);
|
||||
|
||||
if (*keydist & SMP_DIST_ENC_KEY) {
|
||||
struct smp_cmd_encrypt_info enc;
|
||||
struct smp_cmd_master_ident ident;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct smp_ltk *ltk;
|
||||
u8 authenticated;
|
||||
__le16 ediv;
|
||||
__le64 rand;
|
||||
|
||||
get_random_bytes(enc.ltk, sizeof(enc.ltk));
|
||||
get_random_bytes(&ediv, sizeof(ediv));
|
||||
get_random_bytes(ident.rand, sizeof(ident.rand));
|
||||
get_random_bytes(&rand, sizeof(rand));
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
|
||||
|
||||
authenticated = hcon->sec_level == BT_SECURITY_HIGH;
|
||||
hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
|
||||
HCI_SMP_LTK_SLAVE, 1, authenticated,
|
||||
enc.ltk, smp->enc_key_size, ediv, ident.rand);
|
||||
ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type,
|
||||
HCI_SMP_LTK_SLAVE, authenticated, enc.ltk,
|
||||
smp->enc_key_size, ediv, rand);
|
||||
smp->slave_ltk = ltk;
|
||||
|
||||
ident.ediv = ediv;
|
||||
ident.rand = rand;
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
|
||||
|
||||
@@ -996,14 +1314,18 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
|
||||
struct smp_cmd_ident_addr_info addrinfo;
|
||||
struct smp_cmd_ident_info idinfo;
|
||||
|
||||
/* Send a dummy key */
|
||||
get_random_bytes(idinfo.irk, sizeof(idinfo.irk));
|
||||
memcpy(idinfo.irk, hdev->irk, sizeof(idinfo.irk));
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
|
||||
|
||||
/* Just public address */
|
||||
memset(&addrinfo, 0, sizeof(addrinfo));
|
||||
bacpy(&addrinfo.bdaddr, &conn->hcon->src);
|
||||
/* The hci_conn contains the local identity address
|
||||
* after the connection has been established.
|
||||
*
|
||||
* This is true even when the connection has been
|
||||
* established using a resolvable random address.
|
||||
*/
|
||||
bacpy(&addrinfo.bdaddr, &hcon->src);
|
||||
addrinfo.addr_type = hcon->src_type;
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
|
||||
&addrinfo);
|
||||
@@ -1013,20 +1335,33 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
|
||||
|
||||
if (*keydist & SMP_DIST_SIGN) {
|
||||
struct smp_cmd_sign_info sign;
|
||||
struct smp_csrk *csrk;
|
||||
|
||||
/* Send a dummy key */
|
||||
/* Generate a new random key */
|
||||
get_random_bytes(sign.csrk, sizeof(sign.csrk));
|
||||
|
||||
csrk = kzalloc(sizeof(*csrk), GFP_KERNEL);
|
||||
if (csrk) {
|
||||
csrk->master = 0x00;
|
||||
memcpy(csrk->val, sign.csrk, sizeof(csrk->val));
|
||||
}
|
||||
smp->slave_csrk = csrk;
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign);
|
||||
|
||||
*keydist &= ~SMP_DIST_SIGN;
|
||||
}
|
||||
|
||||
if (conn->hcon->out || force) {
|
||||
clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
|
||||
cancel_delayed_work_sync(&conn->security_timer);
|
||||
smp_chan_destroy(conn);
|
||||
}
|
||||
/* If there are still keys to be received wait for them */
|
||||
if ((smp->remote_key_dist & 0x07))
|
||||
return 0;
|
||||
|
||||
clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags);
|
||||
cancel_delayed_work_sync(&conn->security_timer);
|
||||
set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags);
|
||||
smp_notify_keys(conn);
|
||||
|
||||
smp_chan_destroy(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -78,7 +78,7 @@ struct smp_cmd_encrypt_info {
|
||||
#define SMP_CMD_MASTER_IDENT 0x07
|
||||
struct smp_cmd_master_ident {
|
||||
__le16 ediv;
|
||||
__u8 rand[8];
|
||||
__le64 rand;
|
||||
} __packed;
|
||||
|
||||
#define SMP_CMD_IDENT_INFO 0x08
|
||||
@@ -118,6 +118,8 @@ struct smp_cmd_security_req {
|
||||
#define SMP_FLAG_TK_VALID 1
|
||||
#define SMP_FLAG_CFM_PENDING 2
|
||||
#define SMP_FLAG_MITM_AUTH 3
|
||||
#define SMP_FLAG_COMPLETE 4
|
||||
#define SMP_FLAG_INITIATOR 5
|
||||
|
||||
struct smp_chan {
|
||||
struct l2cap_conn *conn;
|
||||
@@ -128,20 +130,31 @@ struct smp_chan {
|
||||
u8 pcnf[16]; /* SMP Pairing Confirm */
|
||||
u8 tk[16]; /* SMP Temporary Key */
|
||||
u8 enc_key_size;
|
||||
u8 remote_key_dist;
|
||||
bdaddr_t id_addr;
|
||||
u8 id_addr_type;
|
||||
u8 irk[16];
|
||||
struct smp_csrk *csrk;
|
||||
struct smp_csrk *slave_csrk;
|
||||
struct smp_ltk *ltk;
|
||||
struct smp_ltk *slave_ltk;
|
||||
struct smp_irk *remote_irk;
|
||||
unsigned long smp_flags;
|
||||
struct crypto_blkcipher *tfm;
|
||||
struct work_struct confirm;
|
||||
struct work_struct random;
|
||||
|
||||
};
|
||||
|
||||
/* SMP Commands */
|
||||
bool smp_sufficient_security(struct hci_conn *hcon, 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_distribute_keys(struct l2cap_conn *conn, __u8 force);
|
||||
int smp_distribute_keys(struct l2cap_conn *conn);
|
||||
int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
|
||||
|
||||
void smp_chan_destroy(struct l2cap_conn *conn);
|
||||
|
||||
bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
|
||||
bdaddr_t *bdaddr);
|
||||
int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa);
|
||||
|
||||
#endif /* __SMP_H */
|
||||
|
Reference in New Issue
Block a user