Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
1c1236e3
K
Kernel
项目概览
openeuler
/
Kernel
大约 1 年 前同步成功
通知
6
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
1c1236e3
编写于
6月 22, 2011
作者:
J
John W. Linville
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/padovan/bluetooth-next-2.6
上级
e10542c4
43f3dc41
变更
15
展开全部
隐藏空白更改
内联
并排
Showing
15 changed file
with
1460 addition
and
458 deletion
+1460
-458
include/net/bluetooth/hci.h
include/net/bluetooth/hci.h
+34
-0
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_core.h
+13
-0
include/net/bluetooth/l2cap.h
include/net/bluetooth/l2cap.h
+62
-33
include/net/bluetooth/mgmt.h
include/net/bluetooth/mgmt.h
+10
-0
include/net/bluetooth/smp.h
include/net/bluetooth/smp.h
+46
-0
net/bluetooth/Kconfig
net/bluetooth/Kconfig
+8
-0
net/bluetooth/Makefile
net/bluetooth/Makefile
+1
-1
net/bluetooth/hci_conn.c
net/bluetooth/hci_conn.c
+53
-3
net/bluetooth/hci_core.c
net/bluetooth/hci_core.c
+113
-0
net/bluetooth/hci_event.c
net/bluetooth/hci_event.c
+69
-0
net/bluetooth/hci_sock.c
net/bluetooth/hci_sock.c
+6
-64
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_core.c
+358
-342
net/bluetooth/l2cap_sock.c
net/bluetooth/l2cap_sock.c
+83
-14
net/bluetooth/mgmt.c
net/bluetooth/mgmt.c
+71
-1
net/bluetooth/smp.c
net/bluetooth/smp.c
+533
-0
未找到文件。
include/net/bluetooth/hci.h
浏览文件 @
1c1236e3
...
...
@@ -745,6 +745,33 @@ struct hci_cp_le_conn_update {
__le16
max_ce_len
;
}
__packed
;
#define HCI_OP_LE_START_ENC 0x2019
struct
hci_cp_le_start_enc
{
__le16
handle
;
__u8
rand
[
8
];
__le16
ediv
;
__u8
ltk
[
16
];
}
__packed
;
#define HCI_OP_LE_LTK_REPLY 0x201a
struct
hci_cp_le_ltk_reply
{
__le16
handle
;
__u8
ltk
[
16
];
}
__packed
;
struct
hci_rp_le_ltk_reply
{
__u8
status
;
__le16
handle
;
}
__packed
;
#define HCI_OP_LE_LTK_NEG_REPLY 0x201b
struct
hci_cp_le_ltk_neg_reply
{
__le16
handle
;
}
__packed
;
struct
hci_rp_le_ltk_neg_reply
{
__u8
status
;
__le16
handle
;
}
__packed
;
/* ---- HCI Events ---- */
#define HCI_EV_INQUIRY_COMPLETE 0x01
...
...
@@ -1035,6 +1062,13 @@ struct hci_ev_le_conn_complete {
__u8
clk_accurancy
;
}
__packed
;
#define HCI_EV_LE_LTK_REQ 0x05
struct
hci_ev_le_ltk_req
{
__le16
handle
;
__u8
random
[
8
];
__le16
ediv
;
}
__packed
;
/* Advertising report event types */
#define ADV_IND 0x00
#define ADV_DIRECT_IND 0x01
...
...
include/net/bluetooth/hci_core.h
浏览文件 @
1c1236e3
...
...
@@ -177,6 +177,8 @@ struct hci_dev {
__u16
init_last_cmd
;
struct
crypto_blkcipher
*
tfm
;
struct
inquiry_cache
inq_cache
;
struct
hci_conn_hash
conn_hash
;
struct
list_head
blacklist
;
...
...
@@ -247,6 +249,7 @@ struct hci_conn {
__u8
power_save
;
__u16
disc_timeout
;
unsigned
long
pend
;
__u8
ltk
[
16
];
__u8
remote_cap
;
__u8
remote_oob
;
...
...
@@ -526,6 +529,8 @@ int hci_inquiry(void __user *arg);
struct
bdaddr_list
*
hci_blacklist_lookup
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
);
int
hci_blacklist_clear
(
struct
hci_dev
*
hdev
);
int
hci_blacklist_add
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
);
int
hci_blacklist_del
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
);
int
hci_uuids_clear
(
struct
hci_dev
*
hdev
);
...
...
@@ -742,6 +747,9 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
if
(
conn
->
sec_level
==
BT_SECURITY_SDP
)
conn
->
sec_level
=
BT_SECURITY_LOW
;
if
(
conn
->
pending_sec_level
>
conn
->
sec_level
)
conn
->
sec_level
=
conn
->
pending_sec_level
;
hci_proto_encrypt_cfm
(
conn
,
status
,
encrypt
);
read_lock_bh
(
&
hci_cb_list_lock
);
...
...
@@ -859,4 +867,9 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result);
void
hci_le_conn_update
(
struct
hci_conn
*
conn
,
u16
min
,
u16
max
,
u16
latency
,
u16
to_multiplier
);
void
hci_le_start_enc
(
struct
hci_conn
*
conn
,
__le16
ediv
,
__u8
rand
[
8
],
__u8
ltk
[
16
]);
void
hci_le_ltk_reply
(
struct
hci_conn
*
conn
,
u8
ltk
[
16
]);
void
hci_le_ltk_neg_reply
(
struct
hci_conn
*
conn
);
#endif
/* __HCI_CORE_H */
include/net/bluetooth/l2cap.h
浏览文件 @
1c1236e3
...
...
@@ -287,6 +287,10 @@ struct l2cap_chan {
struct
l2cap_conn
*
conn
;
__u8
state
;
atomic_t
refcnt
;
__le16
psm
;
__u16
dcid
;
__u16
scid
;
...
...
@@ -320,8 +324,8 @@ struct l2cap_chan {
__u16
monitor_timeout
;
__u16
mps
;
__u8
conf_state
;
__u16
conn_state
;
unsigned
long
conf_state
;
unsigned
long
conn_state
;
__u8
next_tx_seq
;
__u8
expected_ack_seq
;
...
...
@@ -354,6 +358,18 @@ struct l2cap_chan {
struct
list_head
list
;
struct
list_head
global_l
;
void
*
data
;
struct
l2cap_ops
*
ops
;
};
struct
l2cap_ops
{
char
*
name
;
struct
l2cap_chan
*
(
*
new_connection
)
(
void
*
data
);
int
(
*
recv
)
(
void
*
data
,
struct
sk_buff
*
skb
);
void
(
*
close
)
(
void
*
data
);
void
(
*
state_change
)
(
void
*
data
,
int
state
);
};
struct
l2cap_conn
{
...
...
@@ -379,6 +395,15 @@ struct l2cap_conn {
__u8
disc_reason
;
__u8
preq
[
7
];
/* SMP Pairing Request */
__u8
prsp
[
7
];
/* SMP Pairing Response */
__u8
prnd
[
16
];
/* SMP Pairing Random */
__u8
pcnf
[
16
];
/* SMP Pairing Confirm */
__u8
tk
[
16
];
/* SMP Temporary Key */
__u8
smp_key_size
;
struct
timer_list
security_timer
;
struct
list_head
chan_l
;
rwlock_t
chan_lock
;
};
...
...
@@ -399,36 +424,45 @@ struct l2cap_pinfo {
struct
l2cap_chan
*
chan
;
};
#define L2CAP_CONF_REQ_SENT 0x01
#define L2CAP_CONF_INPUT_DONE 0x02
#define L2CAP_CONF_OUTPUT_DONE 0x04
#define L2CAP_CONF_MTU_DONE 0x08
#define L2CAP_CONF_MODE_DONE 0x10
#define L2CAP_CONF_CONNECT_PEND 0x20
#define L2CAP_CONF_NO_FCS_RECV 0x40
#define L2CAP_CONF_STATE2_DEVICE 0x80
enum
{
CONF_REQ_SENT
,
CONF_INPUT_DONE
,
CONF_OUTPUT_DONE
,
CONF_MTU_DONE
,
CONF_MODE_DONE
,
CONF_CONNECT_PEND
,
CONF_NO_FCS_RECV
,
CONF_STATE2_DEVICE
,
};
#define L2CAP_CONF_MAX_CONF_REQ 2
#define L2CAP_CONF_MAX_CONF_RSP 2
#define L2CAP_CONN_SAR_SDU 0x0001
#define L2CAP_CONN_SREJ_SENT 0x0002
#define L2CAP_CONN_WAIT_F 0x0004
#define L2CAP_CONN_SREJ_ACT 0x0008
#define L2CAP_CONN_SEND_PBIT 0x0010
#define L2CAP_CONN_REMOTE_BUSY 0x0020
#define L2CAP_CONN_LOCAL_BUSY 0x0040
#define L2CAP_CONN_REJ_ACT 0x0080
#define L2CAP_CONN_SEND_FBIT 0x0100
#define L2CAP_CONN_RNR_SENT 0x0200
#define L2CAP_CONN_SAR_RETRY 0x0400
#define __mod_retrans_timer() mod_timer(&chan->retrans_timer, \
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
#define __mod_monitor_timer() mod_timer(&chan->monitor_timer, \
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO));
#define __mod_ack_timer() mod_timer(&chan->ack_timer, \
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO));
enum
{
CONN_SAR_SDU
,
CONN_SREJ_SENT
,
CONN_WAIT_F
,
CONN_SREJ_ACT
,
CONN_SEND_PBIT
,
CONN_REMOTE_BUSY
,
CONN_LOCAL_BUSY
,
CONN_REJ_ACT
,
CONN_SEND_FBIT
,
CONN_RNR_SENT
,
CONN_SAR_RETRY
,
};
#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
#define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
L2CAP_DEFAULT_RETRANS_TO);
#define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer)
#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \
L2CAP_DEFAULT_MONITOR_TO);
#define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer)
#define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \
L2CAP_DEFAULT_ACK_TO);
#define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer)
static
inline
int
l2cap_tx_window_full
(
struct
l2cap_chan
*
ch
)
{
...
...
@@ -459,11 +493,6 @@ int __l2cap_wait_ack(struct sock *sk);
int
l2cap_add_psm
(
struct
l2cap_chan
*
chan
,
bdaddr_t
*
src
,
__le16
psm
);
int
l2cap_add_scid
(
struct
l2cap_chan
*
chan
,
__u16
scid
);
void
l2cap_sock_kill
(
struct
sock
*
sk
);
void
l2cap_sock_init
(
struct
sock
*
sk
,
struct
sock
*
parent
);
struct
sock
*
l2cap_sock_alloc
(
struct
net
*
net
,
struct
socket
*
sock
,
int
proto
,
gfp_t
prio
);
struct
l2cap_chan
*
l2cap_chan_create
(
struct
sock
*
sk
);
void
l2cap_chan_close
(
struct
l2cap_chan
*
chan
,
int
reason
);
void
l2cap_chan_destroy
(
struct
l2cap_chan
*
chan
);
...
...
include/net/bluetooth/mgmt.h
浏览文件 @
1c1236e3
...
...
@@ -199,6 +199,16 @@ struct mgmt_cp_remove_remote_oob_data {
#define MGMT_OP_STOP_DISCOVERY 0x001C
#define MGMT_OP_BLOCK_DEVICE 0x001D
struct
mgmt_cp_block_device
{
bdaddr_t
bdaddr
;
}
__packed
;
#define MGMT_OP_UNBLOCK_DEVICE 0x001E
struct
mgmt_cp_unblock_device
{
bdaddr_t
bdaddr
;
}
__packed
;
#define MGMT_EV_CMD_COMPLETE 0x0001
struct
mgmt_ev_cmd_complete
{
__le16
opcode
;
...
...
include/net/bluetooth/smp.h
浏览文件 @
1c1236e3
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
#ifndef __SMP_H
#define __SMP_H
...
...
@@ -16,6 +38,23 @@ struct smp_cmd_pairing {
__u8
resp_key_dist
;
}
__packed
;
#define SMP_IO_DISPLAY_ONLY 0x00
#define SMP_IO_DISPLAY_YESNO 0x01
#define SMP_IO_KEYBOARD_ONLY 0x02
#define SMP_IO_NO_INPUT_OUTPUT 0x03
#define SMP_IO_KEYBOARD_DISPLAY 0x04
#define SMP_OOB_NOT_PRESENT 0x00
#define SMP_OOB_PRESENT 0x01
#define SMP_DIST_ENC_KEY 0x01
#define SMP_DIST_ID_KEY 0x02
#define SMP_DIST_SIGN 0x04
#define SMP_AUTH_NONE 0x00
#define SMP_AUTH_BONDING 0x01
#define SMP_AUTH_MITM 0x04
#define SMP_CMD_PAIRING_CONFIRM 0x03
struct
smp_cmd_pairing_confirm
{
__u8
confirm_val
[
16
];
...
...
@@ -73,4 +112,11 @@ struct smp_cmd_security_req {
#define SMP_UNSPECIFIED 0x08
#define SMP_REPEATED_ATTEMPTS 0x09
#define SMP_MIN_ENC_KEY_SIZE 7
#define SMP_MAX_ENC_KEY_SIZE 16
/* SMP Commands */
int
smp_conn_security
(
struct
l2cap_conn
*
conn
,
__u8
sec_level
);
int
smp_sig_channel
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
);
#endif
/* __SMP_H */
net/bluetooth/Kconfig
浏览文件 @
1c1236e3
...
...
@@ -22,6 +22,7 @@ menuconfig BT
BNEP Module (Bluetooth Network Encapsulation Protocol)
CMTP Module (CAPI Message Transport Protocol)
HIDP Module (Human Interface Device Protocol)
SMP Module (Security Manager Protocol)
Say Y here to compile Bluetooth support into the kernel or say M to
compile it as module (bluetooth).
...
...
@@ -36,11 +37,18 @@ if BT != n
config BT_L2CAP
bool "L2CAP protocol support"
select CRC16
select CRYPTO
select CRYPTO_BLKCIPHER
select CRYPTO_AES
select CRYPTO_ECB
help
L2CAP (Logical Link Control and Adaptation Protocol) provides
connection oriented and connection-less data transport. L2CAP
support is required for most Bluetooth applications.
Also included is support for SMP (Security Manager Protocol) which
is the security layer on top of LE (Low Energy) links.
config BT_SCO
bool "SCO links support"
help
...
...
net/bluetooth/Makefile
浏览文件 @
1c1236e3
...
...
@@ -9,5 +9,5 @@ obj-$(CONFIG_BT_CMTP) += cmtp/
obj-$(CONFIG_BT_HIDP)
+=
hidp/
bluetooth-y
:=
af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o hci_sock.o hci_sysfs.o lib.o
bluetooth-$(CONFIG_BT_L2CAP)
+=
l2cap_core.o l2cap_sock.o
bluetooth-$(CONFIG_BT_L2CAP)
+=
l2cap_core.o l2cap_sock.o
smp.o
bluetooth-$(CONFIG_BT_SCO)
+=
sco.o
net/bluetooth/hci_conn.c
浏览文件 @
1c1236e3
...
...
@@ -53,6 +53,7 @@ static void hci_le_connect(struct hci_conn *conn)
conn
->
state
=
BT_CONNECT
;
conn
->
out
=
1
;
conn
->
link_mode
|=
HCI_LM_MASTER
;
conn
->
sec_level
=
BT_SECURITY_LOW
;
memset
(
&
cp
,
0
,
sizeof
(
cp
));
cp
.
scan_interval
=
cpu_to_le16
(
0x0004
);
...
...
@@ -204,6 +205,55 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
}
EXPORT_SYMBOL
(
hci_le_conn_update
);
void
hci_le_start_enc
(
struct
hci_conn
*
conn
,
__le16
ediv
,
__u8
rand
[
8
],
__u8
ltk
[
16
])
{
struct
hci_dev
*
hdev
=
conn
->
hdev
;
struct
hci_cp_le_start_enc
cp
;
BT_DBG
(
"%p"
,
conn
);
memset
(
&
cp
,
0
,
sizeof
(
cp
));
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
memcpy
(
cp
.
ltk
,
ltk
,
sizeof
(
cp
.
ltk
));
cp
.
ediv
=
ediv
;
memcpy
(
cp
.
rand
,
rand
,
sizeof
(
rand
));
hci_send_cmd
(
hdev
,
HCI_OP_LE_START_ENC
,
sizeof
(
cp
),
&
cp
);
}
EXPORT_SYMBOL
(
hci_le_start_enc
);
void
hci_le_ltk_reply
(
struct
hci_conn
*
conn
,
u8
ltk
[
16
])
{
struct
hci_dev
*
hdev
=
conn
->
hdev
;
struct
hci_cp_le_ltk_reply
cp
;
BT_DBG
(
"%p"
,
conn
);
memset
(
&
cp
,
0
,
sizeof
(
cp
));
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
memcpy
(
cp
.
ltk
,
ltk
,
sizeof
(
ltk
));
hci_send_cmd
(
hdev
,
HCI_OP_LE_LTK_REPLY
,
sizeof
(
cp
),
&
cp
);
}
EXPORT_SYMBOL
(
hci_le_ltk_reply
);
void
hci_le_ltk_neg_reply
(
struct
hci_conn
*
conn
)
{
struct
hci_dev
*
hdev
=
conn
->
hdev
;
struct
hci_cp_le_ltk_neg_reply
cp
;
BT_DBG
(
"%p"
,
conn
);
memset
(
&
cp
,
0
,
sizeof
(
cp
));
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
hci_send_cmd
(
hdev
,
HCI_OP_LE_LTK_NEG_REPLY
,
sizeof
(
cp
),
&
cp
);
}
/* Device _must_ be locked */
void
hci_sco_setup
(
struct
hci_conn
*
conn
,
__u8
status
)
{
...
...
@@ -620,11 +670,11 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
goto
encrypt
;
auth:
if
(
test_
and_set_
bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
pend
))
if
(
test_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
pend
))
return
0
;
hci_conn_auth
(
conn
,
sec_level
,
auth_type
);
return
0
;
if
(
!
hci_conn_auth
(
conn
,
sec_level
,
auth_type
))
return
0
;
encrypt:
if
(
conn
->
link_mode
&
HCI_LM_ENCRYPT
)
...
...
net/bluetooth/hci_core.c
浏览文件 @
1c1236e3
...
...
@@ -42,6 +42,7 @@
#include <linux/notifier.h>
#include <linux/rfkill.h>
#include <linux/timer.h>
#include <linux/crypto.h>
#include <net/sock.h>
#include <asm/system.h>
...
...
@@ -59,6 +60,8 @@ static void hci_tx_task(unsigned long arg);
static
DEFINE_RWLOCK
(
hci_task_lock
);
static
int
enable_smp
;
/* HCI device list */
LIST_HEAD
(
hci_dev_list
);
DEFINE_RWLOCK
(
hci_dev_list_lock
);
...
...
@@ -1202,6 +1205,97 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
return
0
;
}
struct
bdaddr_list
*
hci_blacklist_lookup
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
)
{
struct
list_head
*
p
;
list_for_each
(
p
,
&
hdev
->
blacklist
)
{
struct
bdaddr_list
*
b
;
b
=
list_entry
(
p
,
struct
bdaddr_list
,
list
);
if
(
bacmp
(
bdaddr
,
&
b
->
bdaddr
)
==
0
)
return
b
;
}
return
NULL
;
}
int
hci_blacklist_clear
(
struct
hci_dev
*
hdev
)
{
struct
list_head
*
p
,
*
n
;
list_for_each_safe
(
p
,
n
,
&
hdev
->
blacklist
)
{
struct
bdaddr_list
*
b
;
b
=
list_entry
(
p
,
struct
bdaddr_list
,
list
);
list_del
(
p
);
kfree
(
b
);
}
return
0
;
}
int
hci_blacklist_add
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
)
{
struct
bdaddr_list
*
entry
;
int
err
;
if
(
bacmp
(
bdaddr
,
BDADDR_ANY
)
==
0
)
return
-
EBADF
;
hci_dev_lock
(
hdev
);
if
(
hci_blacklist_lookup
(
hdev
,
bdaddr
))
{
err
=
-
EEXIST
;
goto
err
;
}
entry
=
kzalloc
(
sizeof
(
struct
bdaddr_list
),
GFP_KERNEL
);
if
(
!
entry
)
{
return
-
ENOMEM
;
goto
err
;
}
bacpy
(
&
entry
->
bdaddr
,
bdaddr
);
list_add
(
&
entry
->
list
,
&
hdev
->
blacklist
);
err
=
0
;
err:
hci_dev_unlock
(
hdev
);
return
err
;
}
int
hci_blacklist_del
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
)
{
struct
bdaddr_list
*
entry
;
int
err
=
0
;
hci_dev_lock
(
hdev
);
if
(
bacmp
(
bdaddr
,
BDADDR_ANY
)
==
0
)
{
hci_blacklist_clear
(
hdev
);
goto
done
;
}
entry
=
hci_blacklist_lookup
(
hdev
,
bdaddr
);
if
(
!
entry
)
{
err
=
-
ENOENT
;
goto
done
;
}
list_del
(
&
entry
->
list
);
kfree
(
entry
);
done:
hci_dev_unlock
(
hdev
);
return
err
;
}
static
void
hci_clear_adv_cache
(
unsigned
long
arg
)
{
struct
hci_dev
*
hdev
=
(
void
*
)
arg
;
...
...
@@ -1274,6 +1368,14 @@ int hci_add_adv_entry(struct hci_dev *hdev,
return
0
;
}
static
struct
crypto_blkcipher
*
alloc_cypher
(
void
)
{
if
(
enable_smp
)
return
crypto_alloc_blkcipher
(
"ecb(aes)"
,
0
,
CRYPTO_ALG_ASYNC
);
return
ERR_PTR
(
-
ENOTSUPP
);
}
/* Register HCI device */
int
hci_register_dev
(
struct
hci_dev
*
hdev
)
{
...
...
@@ -1358,6 +1460,11 @@ int hci_register_dev(struct hci_dev *hdev)
if
(
!
hdev
->
workqueue
)
goto
nomem
;
hdev
->
tfm
=
alloc_cypher
();
if
(
IS_ERR
(
hdev
->
tfm
))
BT_INFO
(
"Failed to load transform for ecb(aes): %ld"
,
PTR_ERR
(
hdev
->
tfm
));
hci_register_sysfs
(
hdev
);
hdev
->
rfkill
=
rfkill_alloc
(
hdev
->
name
,
&
hdev
->
dev
,
...
...
@@ -1406,6 +1513,9 @@ int hci_unregister_dev(struct hci_dev *hdev)
!
test_bit
(
HCI_SETUP
,
&
hdev
->
flags
))
mgmt_index_removed
(
hdev
->
id
);
if
(
!
IS_ERR
(
hdev
->
tfm
))
crypto_free_blkcipher
(
hdev
->
tfm
);
hci_notify
(
hdev
,
HCI_DEV_UNREG
);
if
(
hdev
->
rfkill
)
{
...
...
@@ -2242,3 +2352,6 @@ static void hci_cmd_task(unsigned long arg)
}
}
}
module_param
(
enable_smp
,
bool
,
0644
);
MODULE_PARM_DESC
(
enable_smp
,
"Enable SMP support (LE only)"
);
net/bluetooth/hci_event.c
浏览文件 @
1c1236e3
...
...
@@ -868,6 +868,30 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
hci_dev_unlock
(
hdev
);
}
static
void
hci_cc_le_ltk_reply
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_rp_le_ltk_reply
*
rp
=
(
void
*
)
skb
->
data
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
rp
->
status
);
if
(
rp
->
status
)
return
;
hci_req_complete
(
hdev
,
HCI_OP_LE_LTK_REPLY
,
rp
->
status
);
}
static
void
hci_cc_le_ltk_neg_reply
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_rp_le_ltk_neg_reply
*
rp
=
(
void
*
)
skb
->
data
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
rp
->
status
);
if
(
rp
->
status
)
return
;
hci_req_complete
(
hdev
,
HCI_OP_LE_LTK_NEG_REPLY
,
rp
->
status
);
}
static
inline
void
hci_cs_inquiry
(
struct
hci_dev
*
hdev
,
__u8
status
)
{
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
...
...
@@ -1248,6 +1272,11 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
hci_dev_unlock
(
hdev
);
}
static
void
hci_cs_le_start_enc
(
struct
hci_dev
*
hdev
,
u8
status
)
{
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
}
static
inline
void
hci_inquiry_complete_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
__u8
status
=
*
((
__u8
*
)
skb
->
data
);
...
...
@@ -1593,6 +1622,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
/* 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
;
}
...
...
@@ -1856,6 +1886,14 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_le_set_scan_enable
(
hdev
,
skb
);
break
;
case
HCI_OP_LE_LTK_REPLY
:
hci_cc_le_ltk_reply
(
hdev
,
skb
);
break
;
case
HCI_OP_LE_LTK_NEG_REPLY
:
hci_cc_le_ltk_neg_reply
(
hdev
,
skb
);
break
;
default:
BT_DBG
(
"%s opcode 0x%x"
,
hdev
->
name
,
opcode
);
break
;
...
...
@@ -1934,6 +1972,10 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
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%x"
,
hdev
->
name
,
opcode
);
break
;
...
...
@@ -2712,6 +2754,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
mgmt_connected
(
hdev
->
id
,
&
ev
->
bdaddr
);
conn
->
sec_level
=
BT_SECURITY_LOW
;
conn
->
handle
=
__le16_to_cpu
(
ev
->
handle
);
conn
->
state
=
BT_CONNECTED
;
...
...
@@ -2745,6 +2788,28 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
hci_dev_unlock
(
hdev
);
}
static
inline
void
hci_le_ltk_request_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_ev_le_ltk_req
*
ev
=
(
void
*
)
skb
->
data
;
struct
hci_cp_le_ltk_reply
cp
;
struct
hci_conn
*
conn
;
BT_DBG
(
"%s handle %d"
,
hdev
->
name
,
cpu_to_le16
(
ev
->
handle
));
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
ev
->
handle
));
memset
(
&
cp
,
0
,
sizeof
(
cp
));
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
memcpy
(
cp
.
ltk
,
conn
->
ltk
,
sizeof
(
conn
->
ltk
));
hci_send_cmd
(
hdev
,
HCI_OP_LE_LTK_REPLY
,
sizeof
(
cp
),
&
cp
);
hci_dev_unlock
(
hdev
);
}
static
inline
void
hci_le_meta_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_ev_le_meta
*
le_ev
=
(
void
*
)
skb
->
data
;
...
...
@@ -2760,6 +2825,10 @@ static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_le_adv_report_evt
(
hdev
,
skb
);
break
;
case
HCI_EV_LE_LTK_REQ
:
hci_le_ltk_request_evt
(
hdev
,
skb
);
break
;
default:
break
;
}
...
...
net/bluetooth/hci_sock.c
浏览文件 @
1c1236e3
...
...
@@ -180,82 +180,24 @@ static int hci_sock_release(struct socket *sock)
return
0
;
}
struct
bdaddr_list
*
hci_blacklist_lookup
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
)
{
struct
list_head
*
p
;
list_for_each
(
p
,
&
hdev
->
blacklist
)
{
struct
bdaddr_list
*
b
;
b
=
list_entry
(
p
,
struct
bdaddr_list
,
list
);
if
(
bacmp
(
bdaddr
,
&
b
->
bdaddr
)
==
0
)
return
b
;
}
return
NULL
;
}
static
int
hci_blacklist_add
(
struct
hci_dev
*
hdev
,
void
__user
*
arg
)
static
int
hci_sock_blacklist_add
(
struct
hci_dev
*
hdev
,
void
__user
*
arg
)
{
bdaddr_t
bdaddr
;
struct
bdaddr_list
*
entry
;
if
(
copy_from_user
(
&
bdaddr
,
arg
,
sizeof
(
bdaddr
)))
return
-
EFAULT
;
if
(
bacmp
(
&
bdaddr
,
BDADDR_ANY
)
==
0
)
return
-
EBADF
;
if
(
hci_blacklist_lookup
(
hdev
,
&
bdaddr
))
return
-
EEXIST
;
entry
=
kzalloc
(
sizeof
(
struct
bdaddr_list
),
GFP_KERNEL
);
if
(
!
entry
)
return
-
ENOMEM
;
bacpy
(
&
entry
->
bdaddr
,
&
bdaddr
);
list_add
(
&
entry
->
list
,
&
hdev
->
blacklist
);
return
0
;
}
int
hci_blacklist_clear
(
struct
hci_dev
*
hdev
)
{
struct
list_head
*
p
,
*
n
;
list_for_each_safe
(
p
,
n
,
&
hdev
->
blacklist
)
{
struct
bdaddr_list
*
b
;
b
=
list_entry
(
p
,
struct
bdaddr_list
,
list
);
list_del
(
p
);
kfree
(
b
);
}
return
0
;
return
hci_blacklist_add
(
hdev
,
&
bdaddr
);
}
static
int
hci_blacklist_del
(
struct
hci_dev
*
hdev
,
void
__user
*
arg
)
static
int
hci_
sock_
blacklist_del
(
struct
hci_dev
*
hdev
,
void
__user
*
arg
)
{
bdaddr_t
bdaddr
;
struct
bdaddr_list
*
entry
;
if
(
copy_from_user
(
&
bdaddr
,
arg
,
sizeof
(
bdaddr
)))
return
-
EFAULT
;
if
(
bacmp
(
&
bdaddr
,
BDADDR_ANY
)
==
0
)
return
hci_blacklist_clear
(
hdev
);
entry
=
hci_blacklist_lookup
(
hdev
,
&
bdaddr
);
if
(
!
entry
)
return
-
ENOENT
;
list_del
(
&
entry
->
list
);
kfree
(
entry
);
return
0
;
return
hci_blacklist_del
(
hdev
,
&
bdaddr
);
}
/* Ioctls that require bound socket */
...
...
@@ -290,12 +232,12 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
case
HCIBLOCKADDR
:
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EACCES
;
return
hci_blacklist_add
(
hdev
,
(
void
__user
*
)
arg
);
return
hci_
sock_
blacklist_add
(
hdev
,
(
void
__user
*
)
arg
);
case
HCIUNBLOCKADDR
:
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EACCES
;
return
hci_blacklist_del
(
hdev
,
(
void
__user
*
)
arg
);
return
hci_
sock_
blacklist_del
(
hdev
,
(
void
__user
*
)
arg
);
default:
if
(
hdev
->
ioctl
)
...
...
net/bluetooth/l2cap_core.c
浏览文件 @
1c1236e3
此差异已折叠。
点击以展开。
net/bluetooth/l2cap_sock.c
浏览文件 @
1c1236e3
...
...
@@ -29,8 +29,11 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/smp.h>
static
const
struct
proto_ops
l2cap_sock_ops
;
static
void
l2cap_sock_init
(
struct
sock
*
sk
,
struct
sock
*
parent
);
static
struct
sock
*
l2cap_sock_alloc
(
struct
net
*
net
,
struct
socket
*
sock
,
int
proto
,
gfp_t
prio
);
static
int
l2cap_sock_bind
(
struct
socket
*
sock
,
struct
sockaddr
*
addr
,
int
alen
)
{
...
...
@@ -87,6 +90,8 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
chan
->
sec_level
=
BT_SECURITY_SDP
;
bacpy
(
&
bt_sk
(
sk
)
->
src
,
&
la
.
l2_bdaddr
);
chan
->
state
=
BT_BOUND
;
sk
->
sk_state
=
BT_BOUND
;
done:
...
...
@@ -212,6 +217,8 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
sk
->
sk_max_ack_backlog
=
backlog
;
sk
->
sk_ack_backlog
=
0
;
chan
->
state
=
BT_LISTEN
;
sk
->
sk_state
=
BT_LISTEN
;
done:
...
...
@@ -505,7 +512,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
chan
->
mode
=
opts
.
mode
;
switch
(
chan
->
mode
)
{
case
L2CAP_MODE_BASIC
:
c
han
->
conf_state
&=
~
L2CAP_CONF_STATE2_DEVICE
;
c
lear_bit
(
CONF_STATE2_DEVICE
,
&
chan
->
conf_state
)
;
break
;
case
L2CAP_MODE_ERTM
:
case
L2CAP_MODE_STREAMING
:
...
...
@@ -556,6 +563,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
struct
l2cap_chan
*
chan
=
l2cap_pi
(
sk
)
->
chan
;
struct
bt_security
sec
;
struct
bt_power
pwr
;
struct
l2cap_conn
*
conn
;
int
len
,
err
=
0
;
u32
opt
;
...
...
@@ -592,6 +600,20 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
}
chan
->
sec_level
=
sec
.
level
;
conn
=
chan
->
conn
;
if
(
conn
&&
chan
->
scid
==
L2CAP_CID_LE_DATA
)
{
if
(
!
conn
->
hcon
->
out
)
{
err
=
-
EINVAL
;
break
;
}
if
(
smp_conn_security
(
conn
,
sec
.
level
))
break
;
err
=
0
;
sk
->
sk_state
=
BT_CONFIG
;
}
break
;
case
BT_DEFER_SETUP
:
...
...
@@ -711,7 +733,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
/* Kill socket (only if zapped and orphan)
* Must be called on unlocked socket.
*/
void
l2cap_sock_kill
(
struct
sock
*
sk
)
static
void
l2cap_sock_kill
(
struct
sock
*
sk
)
{
if
(
!
sock_flag
(
sk
,
SOCK_ZAPPED
)
||
sk
->
sk_socket
)
return
;
...
...
@@ -773,6 +795,49 @@ static int l2cap_sock_release(struct socket *sock)
return
err
;
}
static
struct
l2cap_chan
*
l2cap_sock_new_connection_cb
(
void
*
data
)
{
struct
sock
*
sk
,
*
parent
=
data
;
sk
=
l2cap_sock_alloc
(
sock_net
(
parent
),
NULL
,
BTPROTO_L2CAP
,
GFP_ATOMIC
);
if
(
!
sk
)
return
NULL
;
l2cap_sock_init
(
sk
,
parent
);
return
l2cap_pi
(
sk
)
->
chan
;
}
static
int
l2cap_sock_recv_cb
(
void
*
data
,
struct
sk_buff
*
skb
)
{
struct
sock
*
sk
=
data
;
return
sock_queue_rcv_skb
(
sk
,
skb
);
}
static
void
l2cap_sock_close_cb
(
void
*
data
)
{
struct
sock
*
sk
=
data
;
l2cap_sock_kill
(
sk
);
}
static
void
l2cap_sock_state_change_cb
(
void
*
data
,
int
state
)
{
struct
sock
*
sk
=
data
;
sk
->
sk_state
=
state
;
}
static
struct
l2cap_ops
l2cap_chan_ops
=
{
.
name
=
"L2CAP Socket Interface"
,
.
new_connection
=
l2cap_sock_new_connection_cb
,
.
recv
=
l2cap_sock_recv_cb
,
.
close
=
l2cap_sock_close_cb
,
.
state_change
=
l2cap_sock_state_change_cb
,
};
static
void
l2cap_sock_destruct
(
struct
sock
*
sk
)
{
BT_DBG
(
"sk %p"
,
sk
);
...
...
@@ -781,7 +846,7 @@ static void l2cap_sock_destruct(struct sock *sk)
skb_queue_purge
(
&
sk
->
sk_write_queue
);
}
void
l2cap_sock_init
(
struct
sock
*
sk
,
struct
sock
*
parent
)
static
void
l2cap_sock_init
(
struct
sock
*
sk
,
struct
sock
*
parent
)
{
struct
l2cap_pinfo
*
pi
=
l2cap_pi
(
sk
);
struct
l2cap_chan
*
chan
=
pi
->
chan
;
...
...
@@ -826,7 +891,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent)
chan
->
omtu
=
0
;
if
(
!
disable_ertm
&&
sk
->
sk_type
==
SOCK_STREAM
)
{
chan
->
mode
=
L2CAP_MODE_ERTM
;
chan
->
conf_state
|=
L2CAP_CONF_STATE2_DEVICE
;
set_bit
(
CONF_STATE2_DEVICE
,
&
chan
->
conf_state
)
;
}
else
{
chan
->
mode
=
L2CAP_MODE_BASIC
;
}
...
...
@@ -838,10 +903,14 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent)
chan
->
force_reliable
=
0
;
chan
->
flushable
=
BT_FLUSHABLE_OFF
;
chan
->
force_active
=
BT_POWER_FORCE_ACTIVE_ON
;
}
/* Default config options */
chan
->
flush_to
=
L2CAP_DEFAULT_FLUSH_TO
;
chan
->
data
=
sk
;
chan
->
ops
=
&
l2cap_chan_ops
;
}
static
struct
proto
l2cap_proto
=
{
...
...
@@ -850,9 +919,10 @@ static struct proto l2cap_proto = {
.
obj_size
=
sizeof
(
struct
l2cap_pinfo
)
};
struct
sock
*
l2cap_sock_alloc
(
struct
net
*
net
,
struct
socket
*
sock
,
int
proto
,
gfp_t
prio
)
st
atic
st
ruct
sock
*
l2cap_sock_alloc
(
struct
net
*
net
,
struct
socket
*
sock
,
int
proto
,
gfp_t
prio
)
{
struct
sock
*
sk
;
struct
l2cap_chan
*
chan
;
sk
=
sk_alloc
(
net
,
PF_BLUETOOTH
,
prio
,
&
l2cap_proto
);
if
(
!
sk
)
...
...
@@ -869,6 +939,14 @@ struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, g
sk
->
sk_protocol
=
proto
;
sk
->
sk_state
=
BT_OPEN
;
chan
=
l2cap_chan_create
(
sk
);
if
(
!
chan
)
{
l2cap_sock_kill
(
sk
);
return
NULL
;
}
l2cap_pi
(
sk
)
->
chan
=
chan
;
return
sk
;
}
...
...
@@ -876,7 +954,6 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
int
kern
)
{
struct
sock
*
sk
;
struct
l2cap_chan
*
chan
;
BT_DBG
(
"sock %p"
,
sock
);
...
...
@@ -895,14 +972,6 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
if
(
!
sk
)
return
-
ENOMEM
;
chan
=
l2cap_chan_create
(
sk
);
if
(
!
chan
)
{
l2cap_sock_kill
(
sk
);
return
-
ENOMEM
;
}
l2cap_pi
(
sk
)
->
chan
=
chan
;
l2cap_sock_init
(
sk
,
NULL
);
return
0
;
}
...
...
net/bluetooth/mgmt.c
浏览文件 @
1c1236e3
...
...
@@ -990,7 +990,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
put_unaligned_le16
(
conn
->
handle
,
&
dc
.
handle
);
dc
.
reason
=
0x13
;
/* Remote User Terminated Connection */
err
=
hci_send_cmd
(
hdev
,
HCI_OP_DISCONNECT
,
0
,
NULL
);
err
=
hci_send_cmd
(
hdev
,
HCI_OP_DISCONNECT
,
sizeof
(
dc
),
&
dc
);
}
unlock:
...
...
@@ -1666,6 +1666,70 @@ static int stop_discovery(struct sock *sk, u16 index)
return
err
;
}
static
int
block_device
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
)
{
struct
hci_dev
*
hdev
;
struct
mgmt_cp_block_device
*
cp
;
int
err
;
BT_DBG
(
"hci%u"
,
index
);
cp
=
(
void
*
)
data
;
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
EINVAL
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
ENODEV
);
err
=
hci_blacklist_add
(
hdev
,
&
cp
->
bdaddr
);
if
(
err
<
0
)
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
-
err
);
else
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
NULL
,
0
);
hci_dev_put
(
hdev
);
return
err
;
}
static
int
unblock_device
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
)
{
struct
hci_dev
*
hdev
;
struct
mgmt_cp_unblock_device
*
cp
;
int
err
;
BT_DBG
(
"hci%u"
,
index
);
cp
=
(
void
*
)
data
;
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
EINVAL
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
ENODEV
);
err
=
hci_blacklist_del
(
hdev
,
&
cp
->
bdaddr
);
if
(
err
<
0
)
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
-
err
);
else
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
NULL
,
0
);
hci_dev_put
(
hdev
);
return
err
;
}
int
mgmt_control
(
struct
sock
*
sk
,
struct
msghdr
*
msg
,
size_t
msglen
)
{
unsigned
char
*
buf
;
...
...
@@ -1780,6 +1844,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case
MGMT_OP_STOP_DISCOVERY
:
err
=
stop_discovery
(
sk
,
index
);
break
;
case
MGMT_OP_BLOCK_DEVICE
:
err
=
block_device
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
case
MGMT_OP_UNBLOCK_DEVICE
:
err
=
unblock_device
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
default:
BT_DBG
(
"Unknown op %u"
,
opcode
);
err
=
cmd_status
(
sk
,
index
,
opcode
,
0x01
);
...
...
net/bluetooth/smp.c
0 → 100644
浏览文件 @
1c1236e3
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/smp.h>
#include <linux/crypto.h>
#include <crypto/b128ops.h>
#define SMP_TIMEOUT 30000
/* 30 seconds */
static
inline
void
swap128
(
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
])
{
int
i
;
for
(
i
=
0
;
i
<
7
;
i
++
)
dst
[
6
-
i
]
=
src
[
i
];
}
static
int
smp_e
(
struct
crypto_blkcipher
*
tfm
,
const
u8
*
k
,
u8
*
r
)
{
struct
blkcipher_desc
desc
;
struct
scatterlist
sg
;
int
err
,
iv_len
;
unsigned
char
iv
[
128
];
if
(
tfm
==
NULL
)
{
BT_ERR
(
"tfm %p"
,
tfm
);
return
-
EINVAL
;
}
desc
.
tfm
=
tfm
;
desc
.
flags
=
0
;
err
=
crypto_blkcipher_setkey
(
tfm
,
k
,
16
);
if
(
err
)
{
BT_ERR
(
"cipher setkey failed: %d"
,
err
);
return
err
;
}
sg_init_one
(
&
sg
,
r
,
16
);
iv_len
=
crypto_blkcipher_ivsize
(
tfm
);
if
(
iv_len
)
{
memset
(
&
iv
,
0xff
,
iv_len
);
crypto_blkcipher_set_iv
(
tfm
,
iv
,
iv_len
);
}
err
=
crypto_blkcipher_encrypt
(
&
desc
,
&
sg
,
&
sg
,
16
);
if
(
err
)
BT_ERR
(
"Encrypt data error %d"
,
err
);
return
err
;
}
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
])
{
u8
p1
[
16
],
p2
[
16
];
int
err
;
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
);
/* p2 = padding || ia || ra */
baswap
((
bdaddr_t
*
)
(
p2
+
4
),
ia
);
baswap
((
bdaddr_t
*
)
(
p2
+
10
),
ra
);
/* res = r XOR p1 */
u128_xor
((
u128
*
)
res
,
(
u128
*
)
r
,
(
u128
*
)
p1
);
/* res = e(k, res) */
err
=
smp_e
(
tfm
,
k
,
res
);
if
(
err
)
{
BT_ERR
(
"Encrypt data error"
);
return
err
;
}
/* res = res XOR p2 */
u128_xor
((
u128
*
)
res
,
(
u128
*
)
res
,
(
u128
*
)
p2
);
/* res = e(k, res) */
err
=
smp_e
(
tfm
,
k
,
res
);
if
(
err
)
BT_ERR
(
"Encrypt data error"
);
return
err
;
}
static
int
smp_s1
(
struct
crypto_blkcipher
*
tfm
,
u8
k
[
16
],
u8
r1
[
16
],
u8
r2
[
16
],
u8
_r
[
16
])
{
int
err
;
/* Just least significant octets from r1 and r2 are considered */
memcpy
(
_r
,
r1
+
8
,
8
);
memcpy
(
_r
+
8
,
r2
+
8
,
8
);
err
=
smp_e
(
tfm
,
k
,
_r
);
if
(
err
)
BT_ERR
(
"Encrypt data error"
);
return
err
;
}
static
int
smp_rand
(
u8
*
buf
)
{
get_random_bytes
(
buf
,
16
);
return
0
;
}
static
struct
sk_buff
*
smp_build_cmd
(
struct
l2cap_conn
*
conn
,
u8
code
,
u16
dlen
,
void
*
data
)
{
struct
sk_buff
*
skb
;
struct
l2cap_hdr
*
lh
;
int
len
;
len
=
L2CAP_HDR_SIZE
+
sizeof
(
code
)
+
dlen
;
if
(
len
>
conn
->
mtu
)
return
NULL
;
skb
=
bt_skb_alloc
(
len
,
GFP_ATOMIC
);
if
(
!
skb
)
return
NULL
;
lh
=
(
struct
l2cap_hdr
*
)
skb_put
(
skb
,
L2CAP_HDR_SIZE
);
lh
->
len
=
cpu_to_le16
(
sizeof
(
code
)
+
dlen
);
lh
->
cid
=
cpu_to_le16
(
L2CAP_CID_SMP
);
memcpy
(
skb_put
(
skb
,
sizeof
(
code
)),
&
code
,
sizeof
(
code
));
memcpy
(
skb_put
(
skb
,
dlen
),
data
,
dlen
);
return
skb
;
}
static
void
smp_send_cmd
(
struct
l2cap_conn
*
conn
,
u8
code
,
u16
len
,
void
*
data
)
{
struct
sk_buff
*
skb
=
smp_build_cmd
(
conn
,
code
,
len
,
data
);
BT_DBG
(
"code 0x%2.2x"
,
code
);
if
(
!
skb
)
return
;
hci_send_acl
(
conn
->
hcon
,
skb
,
0
);
}
static
__u8
seclevel_to_authreq
(
__u8
level
)
{
switch
(
level
)
{
case
BT_SECURITY_HIGH
:
/* Right now we don't support bonding */
return
SMP_AUTH_MITM
;
default:
return
SMP_AUTH_NONE
;
}
}
static
void
build_pairing_cmd
(
struct
l2cap_conn
*
conn
,
struct
smp_cmd_pairing
*
cmd
,
__u8
authreq
)
{
cmd
->
io_capability
=
conn
->
hcon
->
io_capability
;
cmd
->
oob_flag
=
SMP_OOB_NOT_PRESENT
;
cmd
->
max_key_size
=
SMP_MAX_ENC_KEY_SIZE
;
cmd
->
init_key_dist
=
0x00
;
cmd
->
resp_key_dist
=
0x00
;
cmd
->
auth_req
=
authreq
;
}
static
u8
check_enc_key_size
(
struct
l2cap_conn
*
conn
,
__u8
max_key_size
)
{
if
((
max_key_size
>
SMP_MAX_ENC_KEY_SIZE
)
||
(
max_key_size
<
SMP_MIN_ENC_KEY_SIZE
))
return
SMP_ENC_KEY_SIZE
;
conn
->
smp_key_size
=
max_key_size
;
return
0
;
}
static
u8
smp_cmd_pairing_req
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
struct
smp_cmd_pairing
rsp
,
*
req
=
(
void
*
)
skb
->
data
;
u8
key_size
;
BT_DBG
(
"conn %p"
,
conn
);
conn
->
preq
[
0
]
=
SMP_CMD_PAIRING_REQ
;
memcpy
(
&
conn
->
preq
[
1
],
req
,
sizeof
(
*
req
));
skb_pull
(
skb
,
sizeof
(
*
req
));
if
(
req
->
oob_flag
)
return
SMP_OOB_NOT_AVAIL
;
/* We didn't start the pairing, so no requirements */
build_pairing_cmd
(
conn
,
&
rsp
,
SMP_AUTH_NONE
);
key_size
=
min
(
req
->
max_key_size
,
rsp
.
max_key_size
);
if
(
check_enc_key_size
(
conn
,
key_size
))
return
SMP_ENC_KEY_SIZE
;
/* Just works */
memset
(
conn
->
tk
,
0
,
sizeof
(
conn
->
tk
));
conn
->
prsp
[
0
]
=
SMP_CMD_PAIRING_RSP
;
memcpy
(
&
conn
->
prsp
[
1
],
&
rsp
,
sizeof
(
rsp
));
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_RSP
,
sizeof
(
rsp
),
&
rsp
);
mod_timer
(
&
conn
->
security_timer
,
jiffies
+
msecs_to_jiffies
(
SMP_TIMEOUT
));
return
0
;
}
static
u8
smp_cmd_pairing_rsp
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
struct
smp_cmd_pairing
*
req
,
*
rsp
=
(
void
*
)
skb
->
data
;
struct
smp_cmd_pairing_confirm
cp
;
struct
crypto_blkcipher
*
tfm
=
conn
->
hcon
->
hdev
->
tfm
;
int
ret
;
u8
res
[
16
],
key_size
;
BT_DBG
(
"conn %p"
,
conn
);
skb_pull
(
skb
,
sizeof
(
*
rsp
));
req
=
(
void
*
)
&
conn
->
preq
[
1
];
key_size
=
min
(
req
->
max_key_size
,
rsp
->
max_key_size
);
if
(
check_enc_key_size
(
conn
,
key_size
))
return
SMP_ENC_KEY_SIZE
;
if
(
rsp
->
oob_flag
)
return
SMP_OOB_NOT_AVAIL
;
/* Just works */
memset
(
conn
->
tk
,
0
,
sizeof
(
conn
->
tk
));
conn
->
prsp
[
0
]
=
SMP_CMD_PAIRING_RSP
;
memcpy
(
&
conn
->
prsp
[
1
],
rsp
,
sizeof
(
*
rsp
));
ret
=
smp_rand
(
conn
->
prnd
);
if
(
ret
)
return
SMP_UNSPECIFIED
;
ret
=
smp_c1
(
tfm
,
conn
->
tk
,
conn
->
prnd
,
conn
->
preq
,
conn
->
prsp
,
0
,
conn
->
src
,
conn
->
hcon
->
dst_type
,
conn
->
dst
,
res
);
if
(
ret
)
return
SMP_UNSPECIFIED
;
swap128
(
res
,
cp
.
confirm_val
);
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_CONFIRM
,
sizeof
(
cp
),
&
cp
);
return
0
;
}
static
u8
smp_cmd_pairing_confirm
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
struct
crypto_blkcipher
*
tfm
=
conn
->
hcon
->
hdev
->
tfm
;
BT_DBG
(
"conn %p %s"
,
conn
,
conn
->
hcon
->
out
?
"master"
:
"slave"
);
memcpy
(
conn
->
pcnf
,
skb
->
data
,
sizeof
(
conn
->
pcnf
));
skb_pull
(
skb
,
sizeof
(
conn
->
pcnf
));
if
(
conn
->
hcon
->
out
)
{
u8
random
[
16
];
swap128
(
conn
->
prnd
,
random
);
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_RANDOM
,
sizeof
(
random
),
random
);
}
else
{
struct
smp_cmd_pairing_confirm
cp
;
int
ret
;
u8
res
[
16
];
ret
=
smp_rand
(
conn
->
prnd
);
if
(
ret
)
return
SMP_UNSPECIFIED
;
ret
=
smp_c1
(
tfm
,
conn
->
tk
,
conn
->
prnd
,
conn
->
preq
,
conn
->
prsp
,
conn
->
hcon
->
dst_type
,
conn
->
dst
,
0
,
conn
->
src
,
res
);
if
(
ret
)
return
SMP_CONFIRM_FAILED
;
swap128
(
res
,
cp
.
confirm_val
);
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_CONFIRM
,
sizeof
(
cp
),
&
cp
);
}
mod_timer
(
&
conn
->
security_timer
,
jiffies
+
msecs_to_jiffies
(
SMP_TIMEOUT
));
return
0
;
}
static
u8
smp_cmd_pairing_random
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
struct
hci_conn
*
hcon
=
conn
->
hcon
;
struct
crypto_blkcipher
*
tfm
=
hcon
->
hdev
->
tfm
;
int
ret
;
u8
key
[
16
],
res
[
16
],
random
[
16
],
confirm
[
16
];
swap128
(
skb
->
data
,
random
);
skb_pull
(
skb
,
sizeof
(
random
));
memset
(
hcon
->
ltk
,
0
,
sizeof
(
hcon
->
ltk
));
if
(
conn
->
hcon
->
out
)
ret
=
smp_c1
(
tfm
,
conn
->
tk
,
random
,
conn
->
preq
,
conn
->
prsp
,
0
,
conn
->
src
,
conn
->
hcon
->
dst_type
,
conn
->
dst
,
res
);
else
ret
=
smp_c1
(
tfm
,
conn
->
tk
,
random
,
conn
->
preq
,
conn
->
prsp
,
conn
->
hcon
->
dst_type
,
conn
->
dst
,
0
,
conn
->
src
,
res
);
if
(
ret
)
return
SMP_UNSPECIFIED
;
BT_DBG
(
"conn %p %s"
,
conn
,
conn
->
hcon
->
out
?
"master"
:
"slave"
);
swap128
(
res
,
confirm
);
if
(
memcmp
(
conn
->
pcnf
,
confirm
,
sizeof
(
conn
->
pcnf
))
!=
0
)
{
BT_ERR
(
"Pairing failed (confirmation values mismatch)"
);
return
SMP_CONFIRM_FAILED
;
}
if
(
conn
->
hcon
->
out
)
{
__le16
ediv
;
u8
rand
[
8
];
smp_s1
(
tfm
,
conn
->
tk
,
random
,
conn
->
prnd
,
key
);
swap128
(
key
,
hcon
->
ltk
);
memset
(
hcon
->
ltk
+
conn
->
smp_key_size
,
0
,
SMP_MAX_ENC_KEY_SIZE
-
conn
->
smp_key_size
);
memset
(
rand
,
0
,
sizeof
(
rand
));
ediv
=
0
;
hci_le_start_enc
(
hcon
,
ediv
,
rand
,
hcon
->
ltk
);
}
else
{
u8
r
[
16
];
swap128
(
conn
->
prnd
,
r
);
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_RANDOM
,
sizeof
(
r
),
r
);
smp_s1
(
tfm
,
conn
->
tk
,
conn
->
prnd
,
random
,
key
);
swap128
(
key
,
hcon
->
ltk
);
memset
(
hcon
->
ltk
+
conn
->
smp_key_size
,
0
,
SMP_MAX_ENC_KEY_SIZE
-
conn
->
smp_key_size
);
}
return
0
;
}
static
u8
smp_cmd_security_req
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
struct
smp_cmd_security_req
*
rp
=
(
void
*
)
skb
->
data
;
struct
smp_cmd_pairing
cp
;
struct
hci_conn
*
hcon
=
conn
->
hcon
;
BT_DBG
(
"conn %p"
,
conn
);
if
(
test_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
hcon
->
pend
))
return
0
;
skb_pull
(
skb
,
sizeof
(
*
rp
));
memset
(
&
cp
,
0
,
sizeof
(
cp
));
build_pairing_cmd
(
conn
,
&
cp
,
rp
->
auth_req
);
conn
->
preq
[
0
]
=
SMP_CMD_PAIRING_REQ
;
memcpy
(
&
conn
->
preq
[
1
],
&
cp
,
sizeof
(
cp
));
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_REQ
,
sizeof
(
cp
),
&
cp
);
mod_timer
(
&
conn
->
security_timer
,
jiffies
+
msecs_to_jiffies
(
SMP_TIMEOUT
));
set_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
hcon
->
pend
);
return
0
;
}
int
smp_conn_security
(
struct
l2cap_conn
*
conn
,
__u8
sec_level
)
{
struct
hci_conn
*
hcon
=
conn
->
hcon
;
__u8
authreq
;
BT_DBG
(
"conn %p hcon %p level 0x%2.2x"
,
conn
,
hcon
,
sec_level
);
if
(
IS_ERR
(
hcon
->
hdev
->
tfm
))
return
1
;
if
(
test_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
hcon
->
pend
))
return
0
;
if
(
sec_level
==
BT_SECURITY_LOW
)
return
1
;
if
(
hcon
->
sec_level
>=
sec_level
)
return
1
;
authreq
=
seclevel_to_authreq
(
sec_level
);
if
(
hcon
->
link_mode
&
HCI_LM_MASTER
)
{
struct
smp_cmd_pairing
cp
;
build_pairing_cmd
(
conn
,
&
cp
,
authreq
);
conn
->
preq
[
0
]
=
SMP_CMD_PAIRING_REQ
;
memcpy
(
&
conn
->
preq
[
1
],
&
cp
,
sizeof
(
cp
));
mod_timer
(
&
conn
->
security_timer
,
jiffies
+
msecs_to_jiffies
(
SMP_TIMEOUT
));
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_REQ
,
sizeof
(
cp
),
&
cp
);
}
else
{
struct
smp_cmd_security_req
cp
;
cp
.
auth_req
=
authreq
;
smp_send_cmd
(
conn
,
SMP_CMD_SECURITY_REQ
,
sizeof
(
cp
),
&
cp
);
}
hcon
->
pending_sec_level
=
sec_level
;
set_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
hcon
->
pend
);
return
0
;
}
int
smp_sig_channel
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
__u8
code
=
skb
->
data
[
0
];
__u8
reason
;
int
err
=
0
;
if
(
IS_ERR
(
conn
->
hcon
->
hdev
->
tfm
))
{
err
=
PTR_ERR
(
conn
->
hcon
->
hdev
->
tfm
);
reason
=
SMP_PAIRING_NOTSUPP
;
goto
done
;
}
skb_pull
(
skb
,
sizeof
(
code
));
switch
(
code
)
{
case
SMP_CMD_PAIRING_REQ
:
reason
=
smp_cmd_pairing_req
(
conn
,
skb
);
break
;
case
SMP_CMD_PAIRING_FAIL
:
reason
=
0
;
err
=
-
EPERM
;
break
;
case
SMP_CMD_PAIRING_RSP
:
reason
=
smp_cmd_pairing_rsp
(
conn
,
skb
);
break
;
case
SMP_CMD_SECURITY_REQ
:
reason
=
smp_cmd_security_req
(
conn
,
skb
);
break
;
case
SMP_CMD_PAIRING_CONFIRM
:
reason
=
smp_cmd_pairing_confirm
(
conn
,
skb
);
break
;
case
SMP_CMD_PAIRING_RANDOM
:
reason
=
smp_cmd_pairing_random
(
conn
,
skb
);
break
;
case
SMP_CMD_ENCRYPT_INFO
:
case
SMP_CMD_MASTER_IDENT
:
case
SMP_CMD_IDENT_INFO
:
case
SMP_CMD_IDENT_ADDR_INFO
:
case
SMP_CMD_SIGN_INFO
:
default:
BT_DBG
(
"Unknown command code 0x%2.2x"
,
code
);
reason
=
SMP_CMD_NOTSUPP
;
err
=
-
EOPNOTSUPP
;
goto
done
;
}
done:
if
(
reason
)
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_FAIL
,
sizeof
(
reason
),
&
reason
);
kfree_skb
(
skb
);
return
err
;
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录