Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
782a9e31
cloud-kernel
项目概览
openanolis
/
cloud-kernel
1 年多 前同步成功
通知
160
Star
36
Fork
7
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
cloud-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
782a9e31
编写于
1月 04, 2011
作者:
J
John W. Linville
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/padovan/bluetooth-next-2.6
上级
5c4bc1ce
17f9cc31
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
498 addition
and
23 deletion
+498
-23
include/net/bluetooth/bluetooth.h
include/net/bluetooth/bluetooth.h
+1
-0
include/net/bluetooth/hci.h
include/net/bluetooth/hci.h
+4
-0
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_core.h
+8
-1
include/net/bluetooth/mgmt.h
include/net/bluetooth/mgmt.h
+87
-0
net/bluetooth/Makefile
net/bluetooth/Makefile
+1
-1
net/bluetooth/hci_core.c
net/bluetooth/hci_core.c
+14
-3
net/bluetooth/hci_event.c
net/bluetooth/hci_event.c
+23
-10
net/bluetooth/hci_sock.c
net/bluetooth/hci_sock.c
+45
-7
net/bluetooth/l2cap.c
net/bluetooth/l2cap.c
+7
-1
net/bluetooth/mgmt.c
net/bluetooth/mgmt.c
+308
-0
未找到文件。
include/net/bluetooth/bluetooth.h
浏览文件 @
782a9e31
...
...
@@ -144,6 +144,7 @@ struct bt_skb_cb {
__u8
tx_seq
;
__u8
retries
;
__u8
sar
;
unsigned
short
channel
;
};
#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
...
...
include/net/bluetooth/hci.h
浏览文件 @
782a9e31
...
...
@@ -934,9 +934,13 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
struct
sockaddr_hci
{
sa_family_t
hci_family
;
unsigned
short
hci_dev
;
unsigned
short
hci_channel
;
};
#define HCI_DEV_NONE 0xffff
#define HCI_CHANNEL_RAW 0
#define HCI_CHANNEL_CONTROL 1
struct
hci_filter
{
unsigned
long
type_mask
;
unsigned
long
event_mask
[
2
];
...
...
include/net/bluetooth/hci_core.h
浏览文件 @
782a9e31
...
...
@@ -129,6 +129,7 @@ struct hci_dev {
wait_queue_head_t
req_wait_q
;
__u32
req_status
;
__u32
req_result
;
__u16
req_last_cmd
;
struct
inquiry_cache
inq_cache
;
struct
hci_conn_hash
conn_hash
;
...
...
@@ -660,6 +661,11 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
/* ----- HCI Sockets ----- */
void
hci_send_to_sock
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
);
/* Management interface */
int
mgmt_control
(
struct
sock
*
sk
,
struct
msghdr
*
msg
,
size_t
len
);
int
mgmt_index_added
(
u16
index
);
int
mgmt_index_removed
(
u16
index
);
/* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk)
...
...
@@ -668,6 +674,7 @@ struct hci_pinfo {
struct
hci_dev
*
hdev
;
struct
hci_filter
filter
;
__u32
cmsg_mask
;
unsigned
short
channel
;
};
/* HCI security filter */
...
...
@@ -687,6 +694,6 @@ struct hci_sec_filter {
#define hci_req_lock(d) mutex_lock(&d->req_lock)
#define hci_req_unlock(d) mutex_unlock(&d->req_lock)
void
hci_req_complete
(
struct
hci_dev
*
hdev
,
int
result
);
void
hci_req_complete
(
struct
hci_dev
*
hdev
,
__u16
cmd
,
int
result
);
#endif
/* __HCI_CORE_H */
include/net/bluetooth/mgmt.h
0 → 100644
浏览文件 @
782a9e31
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2010 Nokia Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
struct
mgmt_hdr
{
__le16
opcode
;
__le16
len
;
}
__packed
;
#define MGMT_HDR_SIZE 4
#define MGMT_OP_READ_VERSION 0x0001
struct
mgmt_rp_read_version
{
__u8
version
;
__le16
revision
;
}
__packed
;
#define MGMT_OP_READ_INDEX_LIST 0x0003
struct
mgmt_rp_read_index_list
{
__le16
num_controllers
;
__le16
index
[
0
];
}
__packed
;
#define MGMT_OP_READ_INFO 0x0004
struct
mgmt_cp_read_info
{
__le16
index
;
}
__packed
;
struct
mgmt_rp_read_info
{
__le16
index
;
__u8
type
;
__u8
powered
;
__u8
discoverable
;
__u8
pairable
;
__u8
sec_mode
;
bdaddr_t
bdaddr
;
__u8
dev_class
[
3
];
__u8
features
[
8
];
__u16
manufacturer
;
__u8
hci_ver
;
__u16
hci_rev
;
}
__packed
;
#define MGMT_EV_CMD_COMPLETE 0x0001
struct
mgmt_ev_cmd_complete
{
__le16
opcode
;
__u8
data
[
0
];
}
__packed
;
#define MGMT_EV_CMD_STATUS 0x0002
struct
mgmt_ev_cmd_status
{
__u8
status
;
__le16
opcode
;
}
__packed
;
#define MGMT_EV_CONTROLLER_ERROR 0x0003
struct
mgmt_ev_controller_error
{
__le16
index
;
__u8
error_code
;
}
__packed
;
#define MGMT_EV_INDEX_ADDED 0x0004
struct
mgmt_ev_index_added
{
__le16
index
;
}
__packed
;
#define MGMT_EV_INDEX_REMOVED 0x0005
struct
mgmt_ev_index_removed
{
__le16
index
;
}
__packed
;
net/bluetooth/Makefile
浏览文件 @
782a9e31
...
...
@@ -10,4 +10,4 @@ obj-$(CONFIG_BT_BNEP) += bnep/
obj-$(CONFIG_BT_CMTP)
+=
cmtp/
obj-$(CONFIG_BT_HIDP)
+=
hidp/
bluetooth-
objs
:=
af_bluetooth.o hci_core.o hci_conn.o hci_even
t.o hci_sock.o hci_sysfs.o lib.o
bluetooth-
y
:=
af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgm
t.o hci_sock.o hci_sysfs.o lib.o
net/bluetooth/hci_core.c
浏览文件 @
782a9e31
...
...
@@ -91,9 +91,16 @@ static void hci_notify(struct hci_dev *hdev, int event)
/* ---- HCI requests ---- */
void
hci_req_complete
(
struct
hci_dev
*
hdev
,
int
result
)
void
hci_req_complete
(
struct
hci_dev
*
hdev
,
__u16
cmd
,
int
result
)
{
BT_DBG
(
"%s result 0x%2.2x"
,
hdev
->
name
,
result
);
BT_DBG
(
"%s command 0x%04x result 0x%2.2x"
,
hdev
->
name
,
cmd
,
result
);
/* If the request has set req_last_cmd (typical for multi-HCI
* command requests) check if the completed command matches
* this, and if not just return. Single HCI command requests
* typically leave req_last_cmd as 0 */
if
(
hdev
->
req_last_cmd
&&
cmd
!=
hdev
->
req_last_cmd
)
return
;
if
(
hdev
->
req_status
==
HCI_REQ_PEND
)
{
hdev
->
req_result
=
result
;
...
...
@@ -149,7 +156,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
break
;
}
hdev
->
req_status
=
hdev
->
req_result
=
0
;
hdev
->
req_
last_cmd
=
hdev
->
req_
status
=
hdev
->
req_result
=
0
;
BT_DBG
(
"%s end: err %d"
,
hdev
->
name
,
err
);
...
...
@@ -252,6 +259,8 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
/* Connection accept timeout ~20 secs */
param
=
cpu_to_le16
(
0x7d00
);
hci_send_cmd
(
hdev
,
HCI_OP_WRITE_CA_TIMEOUT
,
2
,
&
param
);
hdev
->
req_last_cmd
=
HCI_OP_WRITE_CA_TIMEOUT
;
}
static
void
hci_scan_req
(
struct
hci_dev
*
hdev
,
unsigned
long
opt
)
...
...
@@ -960,6 +969,7 @@ int hci_register_dev(struct hci_dev *hdev)
}
}
mgmt_index_added
(
hdev
->
id
);
hci_notify
(
hdev
,
HCI_DEV_REG
);
return
id
;
...
...
@@ -989,6 +999,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
for
(
i
=
0
;
i
<
NUM_REASSEMBLY
;
i
++
)
kfree_skb
(
hdev
->
reassembly
[
i
]);
mgmt_index_removed
(
hdev
->
id
);
hci_notify
(
hdev
,
HCI_DEV_UNREG
);
if
(
hdev
->
rfkill
)
{
...
...
net/bluetooth/hci_event.c
浏览文件 @
782a9e31
...
...
@@ -58,7 +58,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit
(
HCI_INQUIRY
,
&
hdev
->
flags
);
hci_req_complete
(
hdev
,
status
);
hci_req_complete
(
hdev
,
HCI_OP_INQUIRY_CANCEL
,
status
);
hci_conn_check_pending
(
hdev
);
}
...
...
@@ -174,7 +174,7 @@ static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *s
if
(
!
status
)
hdev
->
link_policy
=
get_unaligned_le16
(
sent
);
hci_req_complete
(
hdev
,
status
);
hci_req_complete
(
hdev
,
HCI_OP_WRITE_DEF_LINK_POLICY
,
status
);
}
static
void
hci_cc_reset
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
...
@@ -183,7 +183,7 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
hci_req_complete
(
hdev
,
status
);
hci_req_complete
(
hdev
,
HCI_OP_RESET
,
status
);
}
static
void
hci_cc_write_local_name
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
...
@@ -235,7 +235,7 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit
(
HCI_AUTH
,
&
hdev
->
flags
);
}
hci_req_complete
(
hdev
,
status
);
hci_req_complete
(
hdev
,
HCI_OP_WRITE_AUTH_ENABLE
,
status
);
}
static
void
hci_cc_write_encrypt_mode
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
...
@@ -258,7 +258,7 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit
(
HCI_ENCRYPT
,
&
hdev
->
flags
);
}
hci_req_complete
(
hdev
,
status
);
hci_req_complete
(
hdev
,
HCI_OP_WRITE_ENCRYPT_MODE
,
status
);
}
static
void
hci_cc_write_scan_enable
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
...
@@ -285,7 +285,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
set_bit
(
HCI_PSCAN
,
&
hdev
->
flags
);
}
hci_req_complete
(
hdev
,
status
);
hci_req_complete
(
hdev
,
HCI_OP_WRITE_SCAN_ENABLE
,
status
);
}
static
void
hci_cc_read_class_of_dev
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
...
@@ -383,7 +383,7 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
hci_req_complete
(
hdev
,
status
);
hci_req_complete
(
hdev
,
HCI_OP_HOST_BUFFER_SIZE
,
status
);
}
static
void
hci_cc_read_ssp_mode
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
...
@@ -536,7 +536,16 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
if
(
!
rp
->
status
)
bacpy
(
&
hdev
->
bdaddr
,
&
rp
->
bdaddr
);
hci_req_complete
(
hdev
,
rp
->
status
);
hci_req_complete
(
hdev
,
HCI_OP_READ_BD_ADDR
,
rp
->
status
);
}
static
void
hci_cc_write_ca_timeout
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
__u8
status
=
*
((
__u8
*
)
skb
->
data
);
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
hci_req_complete
(
hdev
,
HCI_OP_WRITE_CA_TIMEOUT
,
status
);
}
static
inline
void
hci_cs_inquiry
(
struct
hci_dev
*
hdev
,
__u8
status
)
...
...
@@ -544,7 +553,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
if
(
status
)
{
hci_req_complete
(
hdev
,
status
);
hci_req_complete
(
hdev
,
HCI_OP_INQUIRY
,
status
);
hci_conn_check_pending
(
hdev
);
}
else
...
...
@@ -871,7 +880,7 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
clear_bit
(
HCI_INQUIRY
,
&
hdev
->
flags
);
hci_req_complete
(
hdev
,
status
);
hci_req_complete
(
hdev
,
HCI_OP_INQUIRY
,
status
);
hci_conn_check_pending
(
hdev
);
}
...
...
@@ -1379,6 +1388,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_read_bd_addr
(
hdev
,
skb
);
break
;
case
HCI_OP_WRITE_CA_TIMEOUT
:
hci_cc_write_ca_timeout
(
hdev
,
skb
);
break
;
default:
BT_DBG
(
"%s opcode 0x%x"
,
hdev
->
name
,
opcode
);
break
;
...
...
net/bluetooth/hci_sock.c
浏览文件 @
782a9e31
...
...
@@ -49,6 +49,8 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
static
int
enable_mgmt
;
/* ----- HCI socket interface ----- */
static
inline
int
hci_test_bit
(
int
nr
,
void
*
addr
)
...
...
@@ -102,6 +104,12 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
if
(
skb
->
sk
==
sk
)
continue
;
if
(
bt_cb
(
skb
)
->
channel
!=
hci_pi
(
sk
)
->
channel
)
continue
;
if
(
bt_cb
(
skb
)
->
channel
==
HCI_CHANNEL_CONTROL
)
goto
clone
;
/* Apply filter */
flt
=
&
hci_pi
(
sk
)
->
filter
;
...
...
@@ -125,12 +133,14 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
continue
;
}
clone:
nskb
=
skb_clone
(
skb
,
GFP_ATOMIC
);
if
(
!
nskb
)
continue
;
/* Put type byte before the data */
memcpy
(
skb_push
(
nskb
,
1
),
&
bt_cb
(
nskb
)
->
pkt_type
,
1
);
if
(
bt_cb
(
skb
)
->
channel
==
HCI_CHANNEL_RAW
)
memcpy
(
skb_push
(
nskb
,
1
),
&
bt_cb
(
nskb
)
->
pkt_type
,
1
);
if
(
sock_queue_rcv_skb
(
sk
,
nskb
))
kfree_skb
(
nskb
);
...
...
@@ -353,25 +363,38 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long a
static
int
hci_sock_bind
(
struct
socket
*
sock
,
struct
sockaddr
*
addr
,
int
addr_len
)
{
struct
sockaddr_hci
*
haddr
=
(
struct
sockaddr_hci
*
)
addr
;
struct
sockaddr_hci
h
addr
;
struct
sock
*
sk
=
sock
->
sk
;
struct
hci_dev
*
hdev
=
NULL
;
int
err
=
0
;
int
len
,
err
=
0
;
BT_DBG
(
"sock %p sk %p"
,
sock
,
sk
);
if
(
!
haddr
||
haddr
->
hci_family
!=
AF_BLUETOOTH
)
if
(
!
addr
)
return
-
EINVAL
;
memset
(
&
haddr
,
0
,
sizeof
(
haddr
));
len
=
min_t
(
unsigned
int
,
sizeof
(
haddr
),
addr_len
);
memcpy
(
&
haddr
,
addr
,
len
);
if
(
haddr
.
hci_family
!=
AF_BLUETOOTH
)
return
-
EINVAL
;
if
(
haddr
.
hci_channel
>
HCI_CHANNEL_CONTROL
)
return
-
EINVAL
;
if
(
haddr
.
hci_channel
==
HCI_CHANNEL_CONTROL
&&
!
enable_mgmt
)
return
-
EINVAL
;
lock_sock
(
sk
);
if
(
hci_pi
(
sk
)
->
hdev
)
{
if
(
sk
->
sk_state
==
BT_BOUND
||
hci_pi
(
sk
)
->
hdev
)
{
err
=
-
EALREADY
;
goto
done
;
}
if
(
haddr
->
hci_dev
!=
HCI_DEV_NONE
)
{
hdev
=
hci_dev_get
(
haddr
->
hci_dev
);
if
(
haddr
.
hci_dev
!=
HCI_DEV_NONE
)
{
hdev
=
hci_dev_get
(
haddr
.
hci_dev
);
if
(
!
hdev
)
{
err
=
-
ENODEV
;
goto
done
;
...
...
@@ -380,6 +403,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
atomic_inc
(
&
hdev
->
promisc
);
}
hci_pi
(
sk
)
->
channel
=
haddr
.
hci_channel
;
hci_pi
(
sk
)
->
hdev
=
hdev
;
sk
->
sk_state
=
BT_BOUND
;
...
...
@@ -502,6 +526,17 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
lock_sock
(
sk
);
switch
(
hci_pi
(
sk
)
->
channel
)
{
case
HCI_CHANNEL_RAW
:
break
;
case
HCI_CHANNEL_CONTROL
:
err
=
mgmt_control
(
sk
,
msg
,
len
);
goto
done
;
default:
err
=
-
EINVAL
;
goto
done
;
}
hdev
=
hci_pi
(
sk
)
->
hdev
;
if
(
!
hdev
)
{
err
=
-
EBADFD
;
...
...
@@ -831,3 +866,6 @@ void __exit hci_sock_cleanup(void)
proto_unregister
(
&
hci_sk_proto
);
}
module_param
(
enable_mgmt
,
bool
,
0644
);
MODULE_PARM_DESC
(
enable_mgmt
,
"Enable Management interface"
);
net/bluetooth/l2cap.c
浏览文件 @
782a9e31
...
...
@@ -3124,8 +3124,14 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
if
(
!
sk
)
return
-
ENOENT
;
if
(
sk
->
sk_state
==
BT_DISCONN
)
if
(
sk
->
sk_state
!=
BT_CONFIG
)
{
struct
l2cap_cmd_rej
rej
;
rej
.
reason
=
cpu_to_le16
(
0x0002
);
l2cap_send_cmd
(
conn
,
cmd
->
ident
,
L2CAP_COMMAND_REJ
,
sizeof
(
rej
),
&
rej
);
goto
unlock
;
}
/* Reject if config buffer is too small. */
len
=
cmd_len
-
sizeof
(
*
req
);
...
...
net/bluetooth/mgmt.c
0 → 100644
浏览文件 @
782a9e31
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2010 Nokia Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
/* Bluetooth HCI Management interface */
#include <asm/uaccess.h>
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/mgmt.h>
#define MGMT_VERSION 0
#define MGMT_REVISION 1
static
int
cmd_status
(
struct
sock
*
sk
,
u16
cmd
,
u8
status
)
{
struct
sk_buff
*
skb
;
struct
mgmt_hdr
*
hdr
;
struct
mgmt_ev_cmd_status
*
ev
;
BT_DBG
(
"sock %p"
,
sk
);
skb
=
alloc_skb
(
sizeof
(
*
hdr
)
+
sizeof
(
*
ev
),
GFP_ATOMIC
);
if
(
!
skb
)
return
-
ENOMEM
;
hdr
=
(
void
*
)
skb_put
(
skb
,
sizeof
(
*
hdr
));
hdr
->
opcode
=
cpu_to_le16
(
MGMT_EV_CMD_STATUS
);
hdr
->
len
=
cpu_to_le16
(
sizeof
(
*
ev
));
ev
=
(
void
*
)
skb_put
(
skb
,
sizeof
(
*
ev
));
ev
->
status
=
status
;
put_unaligned_le16
(
cmd
,
&
ev
->
opcode
);
if
(
sock_queue_rcv_skb
(
sk
,
skb
)
<
0
)
kfree_skb
(
skb
);
return
0
;
}
static
int
read_version
(
struct
sock
*
sk
)
{
struct
sk_buff
*
skb
;
struct
mgmt_hdr
*
hdr
;
struct
mgmt_ev_cmd_complete
*
ev
;
struct
mgmt_rp_read_version
*
rp
;
BT_DBG
(
"sock %p"
,
sk
);
skb
=
alloc_skb
(
sizeof
(
*
hdr
)
+
sizeof
(
*
ev
)
+
sizeof
(
*
rp
),
GFP_ATOMIC
);
if
(
!
skb
)
return
-
ENOMEM
;
hdr
=
(
void
*
)
skb_put
(
skb
,
sizeof
(
*
hdr
));
hdr
->
opcode
=
cpu_to_le16
(
MGMT_EV_CMD_COMPLETE
);
hdr
->
len
=
cpu_to_le16
(
sizeof
(
*
ev
)
+
sizeof
(
*
rp
));
ev
=
(
void
*
)
skb_put
(
skb
,
sizeof
(
*
ev
));
put_unaligned_le16
(
MGMT_OP_READ_VERSION
,
&
ev
->
opcode
);
rp
=
(
void
*
)
skb_put
(
skb
,
sizeof
(
*
rp
));
rp
->
version
=
MGMT_VERSION
;
put_unaligned_le16
(
MGMT_REVISION
,
&
rp
->
revision
);
if
(
sock_queue_rcv_skb
(
sk
,
skb
)
<
0
)
kfree_skb
(
skb
);
return
0
;
}
static
int
read_index_list
(
struct
sock
*
sk
)
{
struct
sk_buff
*
skb
;
struct
mgmt_hdr
*
hdr
;
struct
mgmt_ev_cmd_complete
*
ev
;
struct
mgmt_rp_read_index_list
*
rp
;
struct
list_head
*
p
;
size_t
body_len
;
u16
count
;
int
i
;
BT_DBG
(
"sock %p"
,
sk
);
read_lock
(
&
hci_dev_list_lock
);
count
=
0
;
list_for_each
(
p
,
&
hci_dev_list
)
{
count
++
;
}
body_len
=
sizeof
(
*
ev
)
+
sizeof
(
*
rp
)
+
(
2
*
count
);
skb
=
alloc_skb
(
sizeof
(
*
hdr
)
+
body_len
,
GFP_ATOMIC
);
if
(
!
skb
)
return
-
ENOMEM
;
hdr
=
(
void
*
)
skb_put
(
skb
,
sizeof
(
*
hdr
));
hdr
->
opcode
=
cpu_to_le16
(
MGMT_EV_CMD_COMPLETE
);
hdr
->
len
=
cpu_to_le16
(
body_len
);
ev
=
(
void
*
)
skb_put
(
skb
,
sizeof
(
*
ev
));
put_unaligned_le16
(
MGMT_OP_READ_INDEX_LIST
,
&
ev
->
opcode
);
rp
=
(
void
*
)
skb_put
(
skb
,
sizeof
(
*
rp
)
+
(
2
*
count
));
put_unaligned_le16
(
count
,
&
rp
->
num_controllers
);
i
=
0
;
list_for_each
(
p
,
&
hci_dev_list
)
{
struct
hci_dev
*
d
=
list_entry
(
p
,
struct
hci_dev
,
list
);
put_unaligned_le16
(
d
->
id
,
&
rp
->
index
[
i
++
]);
BT_DBG
(
"Added hci%u"
,
d
->
id
);
}
read_unlock
(
&
hci_dev_list_lock
);
if
(
sock_queue_rcv_skb
(
sk
,
skb
)
<
0
)
kfree_skb
(
skb
);
return
0
;
}
static
int
read_controller_info
(
struct
sock
*
sk
,
unsigned
char
*
data
,
u16
len
)
{
struct
sk_buff
*
skb
;
struct
mgmt_hdr
*
hdr
;
struct
mgmt_ev_cmd_complete
*
ev
;
struct
mgmt_rp_read_info
*
rp
;
struct
mgmt_cp_read_info
*
cp
;
struct
hci_dev
*
hdev
;
u16
dev_id
;
BT_DBG
(
"sock %p"
,
sk
);
if
(
len
!=
2
)
return
cmd_status
(
sk
,
MGMT_OP_READ_INFO
,
EINVAL
);
skb
=
alloc_skb
(
sizeof
(
*
hdr
)
+
sizeof
(
*
ev
)
+
sizeof
(
*
rp
),
GFP_ATOMIC
);
if
(
!
skb
)
return
-
ENOMEM
;
hdr
=
(
void
*
)
skb_put
(
skb
,
sizeof
(
*
hdr
));
hdr
->
opcode
=
cpu_to_le16
(
MGMT_EV_CMD_COMPLETE
);
hdr
->
len
=
cpu_to_le16
(
sizeof
(
*
ev
)
+
sizeof
(
*
rp
));
ev
=
(
void
*
)
skb_put
(
skb
,
sizeof
(
*
ev
));
put_unaligned_le16
(
MGMT_OP_READ_INFO
,
&
ev
->
opcode
);
rp
=
(
void
*
)
skb_put
(
skb
,
sizeof
(
*
rp
));
cp
=
(
void
*
)
data
;
dev_id
=
get_unaligned_le16
(
&
cp
->
index
);
BT_DBG
(
"request for hci%u"
,
dev_id
);
hdev
=
hci_dev_get
(
dev_id
);
if
(
!
hdev
)
{
kfree_skb
(
skb
);
return
cmd_status
(
sk
,
MGMT_OP_READ_INFO
,
ENODEV
);
}
hci_dev_lock_bh
(
hdev
);
put_unaligned_le16
(
hdev
->
id
,
&
rp
->
index
);
rp
->
type
=
hdev
->
dev_type
;
rp
->
powered
=
test_bit
(
HCI_UP
,
&
hdev
->
flags
);
rp
->
discoverable
=
test_bit
(
HCI_ISCAN
,
&
hdev
->
flags
);
rp
->
pairable
=
test_bit
(
HCI_PSCAN
,
&
hdev
->
flags
);
if
(
test_bit
(
HCI_AUTH
,
&
hdev
->
flags
))
rp
->
sec_mode
=
3
;
else
if
(
hdev
->
ssp_mode
>
0
)
rp
->
sec_mode
=
4
;
else
rp
->
sec_mode
=
2
;
bacpy
(
&
rp
->
bdaddr
,
&
hdev
->
bdaddr
);
memcpy
(
rp
->
features
,
hdev
->
features
,
8
);
memcpy
(
rp
->
dev_class
,
hdev
->
dev_class
,
3
);
put_unaligned_le16
(
hdev
->
manufacturer
,
&
rp
->
manufacturer
);
rp
->
hci_ver
=
hdev
->
hci_ver
;
put_unaligned_le16
(
hdev
->
hci_rev
,
&
rp
->
hci_rev
);
hci_dev_unlock_bh
(
hdev
);
hci_dev_put
(
hdev
);
if
(
sock_queue_rcv_skb
(
sk
,
skb
)
<
0
)
kfree_skb
(
skb
);
return
0
;
}
int
mgmt_control
(
struct
sock
*
sk
,
struct
msghdr
*
msg
,
size_t
msglen
)
{
unsigned
char
*
buf
;
struct
mgmt_hdr
*
hdr
;
u16
opcode
,
len
;
int
err
;
BT_DBG
(
"got %zu bytes"
,
msglen
);
if
(
msglen
<
sizeof
(
*
hdr
))
return
-
EINVAL
;
buf
=
kmalloc
(
msglen
,
GFP_ATOMIC
);
if
(
!
buf
)
return
-
ENOMEM
;
if
(
memcpy_fromiovec
(
buf
,
msg
->
msg_iov
,
msglen
))
{
err
=
-
EFAULT
;
goto
done
;
}
hdr
=
(
struct
mgmt_hdr
*
)
buf
;
opcode
=
get_unaligned_le16
(
&
hdr
->
opcode
);
len
=
get_unaligned_le16
(
&
hdr
->
len
);
if
(
len
!=
msglen
-
sizeof
(
*
hdr
))
{
err
=
-
EINVAL
;
goto
done
;
}
switch
(
opcode
)
{
case
MGMT_OP_READ_VERSION
:
err
=
read_version
(
sk
);
break
;
case
MGMT_OP_READ_INDEX_LIST
:
err
=
read_index_list
(
sk
);
break
;
case
MGMT_OP_READ_INFO
:
err
=
read_controller_info
(
sk
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
default:
BT_DBG
(
"Unknown op %u"
,
opcode
);
err
=
cmd_status
(
sk
,
opcode
,
0x01
);
break
;
}
if
(
err
<
0
)
goto
done
;
err
=
msglen
;
done:
kfree
(
buf
);
return
err
;
}
static
int
mgmt_event
(
u16
event
,
void
*
data
,
u16
data_len
)
{
struct
sk_buff
*
skb
;
struct
mgmt_hdr
*
hdr
;
skb
=
alloc_skb
(
sizeof
(
*
hdr
)
+
data_len
,
GFP_ATOMIC
);
if
(
!
skb
)
return
-
ENOMEM
;
bt_cb
(
skb
)
->
channel
=
HCI_CHANNEL_CONTROL
;
hdr
=
(
void
*
)
skb_put
(
skb
,
sizeof
(
*
hdr
));
hdr
->
opcode
=
cpu_to_le16
(
event
);
hdr
->
len
=
cpu_to_le16
(
data_len
);
memcpy
(
skb_put
(
skb
,
data_len
),
data
,
data_len
);
hci_send_to_sock
(
NULL
,
skb
);
kfree_skb
(
skb
);
return
0
;
}
int
mgmt_index_added
(
u16
index
)
{
struct
mgmt_ev_index_added
ev
;
put_unaligned_le16
(
index
,
&
ev
.
index
);
return
mgmt_event
(
MGMT_EV_INDEX_ADDED
,
&
ev
,
sizeof
(
ev
));
}
int
mgmt_index_removed
(
u16
index
)
{
struct
mgmt_ev_index_added
ev
;
put_unaligned_le16
(
index
,
&
ev
.
index
);
return
mgmt_event
(
MGMT_EV_INDEX_REMOVED
,
&
ev
,
sizeof
(
ev
));
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录