Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
407d819c
Commit
407d819c
authored
Jul 19, 2008
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
git://git.kernel.org/pub/scm/linux/kernel/git/holtmann/bluetooth-2.6
parents
7abbcd6a
b1235d79
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
1112 additions
and
271 deletions
+1112
-271
fs/compat_ioctl.c
fs/compat_ioctl.c
+1
-0
include/net/bluetooth/bluetooth.h
include/net/bluetooth/bluetooth.h
+1
-0
include/net/bluetooth/hci.h
include/net/bluetooth/hci.h
+64
-4
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_core.h
+13
-6
include/net/bluetooth/rfcomm.h
include/net/bluetooth/rfcomm.h
+2
-0
net/bluetooth/af_bluetooth.c
net/bluetooth/af_bluetooth.c
+52
-1
net/bluetooth/bnep/core.c
net/bluetooth/bnep/core.c
+5
-0
net/bluetooth/hci_conn.c
net/bluetooth/hci_conn.c
+76
-20
net/bluetooth/hci_core.c
net/bluetooth/hci_core.c
+29
-13
net/bluetooth/hci_event.c
net/bluetooth/hci_event.c
+454
-58
net/bluetooth/hci_sock.c
net/bluetooth/hci_sock.c
+5
-13
net/bluetooth/hci_sysfs.c
net/bluetooth/hci_sysfs.c
+21
-10
net/bluetooth/hidp/core.c
net/bluetooth/hidp/core.c
+10
-0
net/bluetooth/l2cap.c
net/bluetooth/l2cap.c
+234
-103
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/core.c
+60
-32
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/sock.c
+16
-7
net/bluetooth/rfcomm/tty.c
net/bluetooth/rfcomm/tty.c
+58
-1
net/bluetooth/sco.c
net/bluetooth/sco.c
+11
-3
No files found.
fs/compat_ioctl.c
View file @
407d819c
...
@@ -2346,6 +2346,7 @@ COMPATIBLE_IOCTL(HCIGETDEVLIST)
...
@@ -2346,6 +2346,7 @@ COMPATIBLE_IOCTL(HCIGETDEVLIST)
COMPATIBLE_IOCTL
(
HCIGETDEVINFO
)
COMPATIBLE_IOCTL
(
HCIGETDEVINFO
)
COMPATIBLE_IOCTL
(
HCIGETCONNLIST
)
COMPATIBLE_IOCTL
(
HCIGETCONNLIST
)
COMPATIBLE_IOCTL
(
HCIGETCONNINFO
)
COMPATIBLE_IOCTL
(
HCIGETCONNINFO
)
COMPATIBLE_IOCTL
(
HCIGETAUTHINFO
)
COMPATIBLE_IOCTL
(
HCISETRAW
)
COMPATIBLE_IOCTL
(
HCISETRAW
)
COMPATIBLE_IOCTL
(
HCISETSCAN
)
COMPATIBLE_IOCTL
(
HCISETSCAN
)
COMPATIBLE_IOCTL
(
HCISETAUTH
)
COMPATIBLE_IOCTL
(
HCISETAUTH
)
...
...
include/net/bluetooth/bluetooth.h
View file @
407d819c
...
@@ -121,6 +121,7 @@ void bt_sock_link(struct bt_sock_list *l, struct sock *s);
...
@@ -121,6 +121,7 @@ void bt_sock_link(struct bt_sock_list *l, struct sock *s);
void
bt_sock_unlink
(
struct
bt_sock_list
*
l
,
struct
sock
*
s
);
void
bt_sock_unlink
(
struct
bt_sock_list
*
l
,
struct
sock
*
s
);
int
bt_sock_recvmsg
(
struct
kiocb
*
iocb
,
struct
socket
*
sock
,
struct
msghdr
*
msg
,
size_t
len
,
int
flags
);
int
bt_sock_recvmsg
(
struct
kiocb
*
iocb
,
struct
socket
*
sock
,
struct
msghdr
*
msg
,
size_t
len
,
int
flags
);
uint
bt_sock_poll
(
struct
file
*
file
,
struct
socket
*
sock
,
poll_table
*
wait
);
uint
bt_sock_poll
(
struct
file
*
file
,
struct
socket
*
sock
,
poll_table
*
wait
);
int
bt_sock_ioctl
(
struct
socket
*
sock
,
unsigned
int
cmd
,
unsigned
long
arg
);
int
bt_sock_wait_state
(
struct
sock
*
sk
,
int
state
,
unsigned
long
timeo
);
int
bt_sock_wait_state
(
struct
sock
*
sk
,
int
state
,
unsigned
long
timeo
);
void
bt_accept_enqueue
(
struct
sock
*
parent
,
struct
sock
*
sk
);
void
bt_accept_enqueue
(
struct
sock
*
parent
,
struct
sock
*
sk
);
...
...
include/net/bluetooth/hci.h
View file @
407d819c
...
@@ -72,8 +72,6 @@ enum {
...
@@ -72,8 +72,6 @@ enum {
HCI_INQUIRY
,
HCI_INQUIRY
,
HCI_RAW
,
HCI_RAW
,
HCI_SECMGR
};
};
/* HCI ioctl defines */
/* HCI ioctl defines */
...
@@ -86,6 +84,7 @@ enum {
...
@@ -86,6 +84,7 @@ enum {
#define HCIGETDEVINFO _IOR('H', 211, int)
#define HCIGETDEVINFO _IOR('H', 211, int)
#define HCIGETCONNLIST _IOR('H', 212, int)
#define HCIGETCONNLIST _IOR('H', 212, int)
#define HCIGETCONNINFO _IOR('H', 213, int)
#define HCIGETCONNINFO _IOR('H', 213, int)
#define HCIGETAUTHINFO _IOR('H', 215, int)
#define HCISETRAW _IOW('H', 220, int)
#define HCISETRAW _IOW('H', 220, int)
#define HCISETSCAN _IOW('H', 221, int)
#define HCISETSCAN _IOW('H', 221, int)
...
@@ -97,8 +96,6 @@ enum {
...
@@ -97,8 +96,6 @@ enum {
#define HCISETACLMTU _IOW('H', 227, int)
#define HCISETACLMTU _IOW('H', 227, int)
#define HCISETSCOMTU _IOW('H', 228, int)
#define HCISETSCOMTU _IOW('H', 228, int)
#define HCISETSECMGR _IOW('H', 230, int)
#define HCIINQUIRY _IOR('H', 240, int)
#define HCIINQUIRY _IOR('H', 240, int)
/* HCI timeouts */
/* HCI timeouts */
...
@@ -137,6 +134,8 @@ enum {
...
@@ -137,6 +134,8 @@ enum {
#define ESCO_EV4 0x0010
#define ESCO_EV4 0x0010
#define ESCO_EV5 0x0020
#define ESCO_EV5 0x0020
#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3)
/* ACL flags */
/* ACL flags */
#define ACL_CONT 0x01
#define ACL_CONT 0x01
#define ACL_START 0x02
#define ACL_START 0x02
...
@@ -178,6 +177,8 @@ enum {
...
@@ -178,6 +177,8 @@ enum {
#define LMP_SNIFF_SUBR 0x02
#define LMP_SNIFF_SUBR 0x02
#define LMP_SIMPLE_PAIR 0x08
/* Connection modes */
/* Connection modes */
#define HCI_CM_ACTIVE 0x0000
#define HCI_CM_ACTIVE 0x0000
#define HCI_CM_HOLD 0x0001
#define HCI_CM_HOLD 0x0001
...
@@ -199,6 +200,14 @@ enum {
...
@@ -199,6 +200,14 @@ enum {
#define HCI_LM_RELIABLE 0x0010
#define HCI_LM_RELIABLE 0x0010
#define HCI_LM_SECURE 0x0020
#define HCI_LM_SECURE 0x0020
/* Authentication types */
#define HCI_AT_NO_BONDING 0x00
#define HCI_AT_NO_BONDING_MITM 0x01
#define HCI_AT_DEDICATED_BONDING 0x02
#define HCI_AT_DEDICATED_BONDING_MITM 0x03
#define HCI_AT_GENERAL_BONDING 0x04
#define HCI_AT_GENERAL_BONDING_MITM 0x05
/* ----- HCI Commands ---- */
/* ----- HCI Commands ---- */
#define HCI_OP_INQUIRY 0x0401
#define HCI_OP_INQUIRY 0x0401
struct
hci_cp_inquiry
{
struct
hci_cp_inquiry
{
...
@@ -402,6 +411,17 @@ struct hci_rp_write_link_policy {
...
@@ -402,6 +411,17 @@ struct hci_rp_write_link_policy {
__le16
handle
;
__le16
handle
;
}
__attribute__
((
packed
));
}
__attribute__
((
packed
));
#define HCI_OP_READ_DEF_LINK_POLICY 0x080e
struct
hci_rp_read_def_link_policy
{
__u8
status
;
__le16
policy
;
}
__attribute__
((
packed
));
#define HCI_OP_WRITE_DEF_LINK_POLICY 0x080f
struct
hci_cp_write_def_link_policy
{
__le16
policy
;
}
__attribute__
((
packed
));
#define HCI_OP_SNIFF_SUBRATE 0x0811
#define HCI_OP_SNIFF_SUBRATE 0x0811
struct
hci_cp_sniff_subrate
{
struct
hci_cp_sniff_subrate
{
__le16
handle
;
__le16
handle
;
...
@@ -501,6 +521,17 @@ struct hci_cp_host_buffer_size {
...
@@ -501,6 +521,17 @@ struct hci_cp_host_buffer_size {
__le16
sco_max_pkt
;
__le16
sco_max_pkt
;
}
__attribute__
((
packed
));
}
__attribute__
((
packed
));
#define HCI_OP_READ_SSP_MODE 0x0c55
struct
hci_rp_read_ssp_mode
{
__u8
status
;
__u8
mode
;
}
__attribute__
((
packed
));
#define HCI_OP_WRITE_SSP_MODE 0x0c56
struct
hci_cp_write_ssp_mode
{
__u8
mode
;
}
__attribute__
((
packed
));
#define HCI_OP_READ_LOCAL_VERSION 0x1001
#define HCI_OP_READ_LOCAL_VERSION 0x1001
struct
hci_rp_read_local_version
{
struct
hci_rp_read_local_version
{
__u8
status
;
__u8
status
;
...
@@ -696,6 +727,13 @@ struct hci_ev_clock_offset {
...
@@ -696,6 +727,13 @@ struct hci_ev_clock_offset {
__le16
clock_offset
;
__le16
clock_offset
;
}
__attribute__
((
packed
));
}
__attribute__
((
packed
));
#define HCI_EV_PKT_TYPE_CHANGE 0x1d
struct
hci_ev_pkt_type_change
{
__u8
status
;
__le16
handle
;
__le16
pkt_type
;
}
__attribute__
((
packed
));
#define HCI_EV_PSCAN_REP_MODE 0x20
#define HCI_EV_PSCAN_REP_MODE 0x20
struct
hci_ev_pscan_rep_mode
{
struct
hci_ev_pscan_rep_mode
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
...
@@ -774,6 +812,23 @@ struct extended_inquiry_info {
...
@@ -774,6 +812,23 @@ struct extended_inquiry_info {
__u8
data
[
240
];
__u8
data
[
240
];
}
__attribute__
((
packed
));
}
__attribute__
((
packed
));
#define HCI_EV_IO_CAPA_REQUEST 0x31
struct
hci_ev_io_capa_request
{
bdaddr_t
bdaddr
;
}
__attribute__
((
packed
));
#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36
struct
hci_ev_simple_pair_complete
{
__u8
status
;
bdaddr_t
bdaddr
;
}
__attribute__
((
packed
));
#define HCI_EV_REMOTE_HOST_FEATURES 0x3d
struct
hci_ev_remote_host_features
{
bdaddr_t
bdaddr
;
__u8
features
[
8
];
}
__attribute__
((
packed
));
/* Internal events generated by Bluetooth stack */
/* Internal events generated by Bluetooth stack */
#define HCI_EV_STACK_INTERNAL 0xfd
#define HCI_EV_STACK_INTERNAL 0xfd
struct
hci_ev_stack_internal
{
struct
hci_ev_stack_internal
{
...
@@ -951,6 +1006,11 @@ struct hci_conn_info_req {
...
@@ -951,6 +1006,11 @@ struct hci_conn_info_req {
struct
hci_conn_info
conn_info
[
0
];
struct
hci_conn_info
conn_info
[
0
];
};
};
struct
hci_auth_info_req
{
bdaddr_t
bdaddr
;
__u8
type
;
};
struct
hci_inquiry_req
{
struct
hci_inquiry_req
{
__u16
dev_id
;
__u16
dev_id
;
__u16
flags
;
__u16
flags
;
...
...
include/net/bluetooth/hci_core.h
View file @
407d819c
...
@@ -40,6 +40,7 @@ struct inquiry_data {
...
@@ -40,6 +40,7 @@ struct inquiry_data {
__u8
dev_class
[
3
];
__u8
dev_class
[
3
];
__le16
clock_offset
;
__le16
clock_offset
;
__s8
rssi
;
__s8
rssi
;
__u8
ssp_mode
;
};
};
struct
inquiry_entry
{
struct
inquiry_entry
{
...
@@ -75,6 +76,7 @@ struct hci_dev {
...
@@ -75,6 +76,7 @@ struct hci_dev {
__u8
dev_class
[
3
];
__u8
dev_class
[
3
];
__u8
features
[
8
];
__u8
features
[
8
];
__u8
commands
[
64
];
__u8
commands
[
64
];
__u8
ssp_mode
;
__u8
hci_ver
;
__u8
hci_ver
;
__u16
hci_rev
;
__u16
hci_rev
;
__u16
manufacturer
;
__u16
manufacturer
;
...
@@ -161,9 +163,12 @@ struct hci_conn {
...
@@ -161,9 +163,12 @@ struct hci_conn {
__u8
attempt
;
__u8
attempt
;
__u8
dev_class
[
3
];
__u8
dev_class
[
3
];
__u8
features
[
8
];
__u8
features
[
8
];
__u8
ssp_mode
;
__u16
interval
;
__u16
interval
;
__u16
pkt_type
;
__u16
link_policy
;
__u16
link_policy
;
__u32
link_mode
;
__u32
link_mode
;
__u8
auth_type
;
__u8
power_save
;
__u8
power_save
;
unsigned
long
pend
;
unsigned
long
pend
;
...
@@ -344,7 +349,7 @@ static inline void hci_conn_put(struct hci_conn *conn)
...
@@ -344,7 +349,7 @@ static inline void hci_conn_put(struct hci_conn *conn)
if
(
conn
->
state
==
BT_CONNECTED
)
{
if
(
conn
->
state
==
BT_CONNECTED
)
{
timeo
=
msecs_to_jiffies
(
HCI_DISCONN_TIMEOUT
);
timeo
=
msecs_to_jiffies
(
HCI_DISCONN_TIMEOUT
);
if
(
!
conn
->
out
)
if
(
!
conn
->
out
)
timeo
*=
2
;
timeo
*=
5
;
}
else
}
else
timeo
=
msecs_to_jiffies
(
10
);
timeo
=
msecs_to_jiffies
(
10
);
}
else
}
else
...
@@ -418,6 +423,7 @@ int hci_get_dev_list(void __user *arg);
...
@@ -418,6 +423,7 @@ int hci_get_dev_list(void __user *arg);
int
hci_get_dev_info
(
void
__user
*
arg
);
int
hci_get_dev_info
(
void
__user
*
arg
);
int
hci_get_conn_list
(
void
__user
*
arg
);
int
hci_get_conn_list
(
void
__user
*
arg
);
int
hci_get_conn_info
(
struct
hci_dev
*
hdev
,
void
__user
*
arg
);
int
hci_get_conn_info
(
struct
hci_dev
*
hdev
,
void
__user
*
arg
);
int
hci_get_auth_info
(
struct
hci_dev
*
hdev
,
void
__user
*
arg
);
int
hci_inquiry
(
void
__user
*
arg
);
int
hci_inquiry
(
void
__user
*
arg
);
void
hci_event_packet
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
);
void
hci_event_packet
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
);
...
@@ -459,6 +465,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
...
@@ -459,6 +465,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF)
#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF)
#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO)
#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO)
#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR)
/* ----- HCI protocols ----- */
/* ----- HCI protocols ----- */
struct
hci_proto
{
struct
hci_proto
{
...
@@ -474,7 +481,7 @@ struct hci_proto {
...
@@ -474,7 +481,7 @@ struct hci_proto {
int
(
*
recv_acldata
)
(
struct
hci_conn
*
conn
,
struct
sk_buff
*
skb
,
__u16
flags
);
int
(
*
recv_acldata
)
(
struct
hci_conn
*
conn
,
struct
sk_buff
*
skb
,
__u16
flags
);
int
(
*
recv_scodata
)
(
struct
hci_conn
*
conn
,
struct
sk_buff
*
skb
);
int
(
*
recv_scodata
)
(
struct
hci_conn
*
conn
,
struct
sk_buff
*
skb
);
int
(
*
auth_cfm
)
(
struct
hci_conn
*
conn
,
__u8
status
);
int
(
*
auth_cfm
)
(
struct
hci_conn
*
conn
,
__u8
status
);
int
(
*
encrypt_cfm
)
(
struct
hci_conn
*
conn
,
__u8
status
);
int
(
*
encrypt_cfm
)
(
struct
hci_conn
*
conn
,
__u8
status
,
__u8
encrypt
);
};
};
static
inline
int
hci_proto_connect_ind
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
__u8
type
)
static
inline
int
hci_proto_connect_ind
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
__u8
type
)
...
@@ -532,17 +539,17 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
...
@@ -532,17 +539,17 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
hp
->
auth_cfm
(
conn
,
status
);
hp
->
auth_cfm
(
conn
,
status
);
}
}
static
inline
void
hci_proto_encrypt_cfm
(
struct
hci_conn
*
conn
,
__u8
status
)
static
inline
void
hci_proto_encrypt_cfm
(
struct
hci_conn
*
conn
,
__u8
status
,
__u8
encrypt
)
{
{
register
struct
hci_proto
*
hp
;
register
struct
hci_proto
*
hp
;
hp
=
hci_proto
[
HCI_PROTO_L2CAP
];
hp
=
hci_proto
[
HCI_PROTO_L2CAP
];
if
(
hp
&&
hp
->
encrypt_cfm
)
if
(
hp
&&
hp
->
encrypt_cfm
)
hp
->
encrypt_cfm
(
conn
,
status
);
hp
->
encrypt_cfm
(
conn
,
status
,
encrypt
);
hp
=
hci_proto
[
HCI_PROTO_SCO
];
hp
=
hci_proto
[
HCI_PROTO_SCO
];
if
(
hp
&&
hp
->
encrypt_cfm
)
if
(
hp
&&
hp
->
encrypt_cfm
)
hp
->
encrypt_cfm
(
conn
,
status
);
hp
->
encrypt_cfm
(
conn
,
status
,
encrypt
);
}
}
int
hci_register_proto
(
struct
hci_proto
*
hproto
);
int
hci_register_proto
(
struct
hci_proto
*
hproto
);
...
@@ -579,7 +586,7 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encr
...
@@ -579,7 +586,7 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encr
{
{
struct
list_head
*
p
;
struct
list_head
*
p
;
hci_proto_encrypt_cfm
(
conn
,
status
);
hci_proto_encrypt_cfm
(
conn
,
status
,
encrypt
);
read_lock_bh
(
&
hci_cb_list_lock
);
read_lock_bh
(
&
hci_cb_list_lock
);
list_for_each
(
p
,
&
hci_cb_list
)
{
list_for_each
(
p
,
&
hci_cb_list
)
{
...
...
include/net/bluetooth/rfcomm.h
View file @
407d819c
...
@@ -180,7 +180,9 @@ struct rfcomm_dlc {
...
@@ -180,7 +180,9 @@ struct rfcomm_dlc {
u8
addr
;
u8
addr
;
u8
priority
;
u8
priority
;
u8
v24_sig
;
u8
v24_sig
;
u8
remote_v24_sig
;
u8
mscex
;
u8
mscex
;
u8
out
;
u32
link_mode
;
u32
link_mode
;
...
...
net/bluetooth/af_bluetooth.c
View file @
407d819c
...
@@ -36,6 +36,7 @@
...
@@ -36,6 +36,7 @@
#include <linux/init.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/poll.h>
#include <net/sock.h>
#include <net/sock.h>
#include <asm/ioctls.h>
#if defined(CONFIG_KMOD)
#if defined(CONFIG_KMOD)
#include <linux/kmod.h>
#include <linux/kmod.h>
...
@@ -48,7 +49,7 @@
...
@@ -48,7 +49,7 @@
#define BT_DBG(D...)
#define BT_DBG(D...)
#endif
#endif
#define VERSION "2.1
1
"
#define VERSION "2.1
2
"
/* Bluetooth sockets */
/* Bluetooth sockets */
#define BT_MAX_PROTO 8
#define BT_MAX_PROTO 8
...
@@ -266,6 +267,8 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
...
@@ -266,6 +267,8 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
skb_reset_transport_header
(
skb
);
skb_reset_transport_header
(
skb
);
err
=
skb_copy_datagram_iovec
(
skb
,
0
,
msg
->
msg_iov
,
copied
);
err
=
skb_copy_datagram_iovec
(
skb
,
0
,
msg
->
msg_iov
,
copied
);
if
(
err
==
0
)
sock_recv_timestamp
(
msg
,
sk
,
skb
);
skb_free_datagram
(
sk
,
skb
);
skb_free_datagram
(
sk
,
skb
);
...
@@ -329,6 +332,54 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
...
@@ -329,6 +332,54 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
}
}
EXPORT_SYMBOL
(
bt_sock_poll
);
EXPORT_SYMBOL
(
bt_sock_poll
);
int
bt_sock_ioctl
(
struct
socket
*
sock
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sk_buff
*
skb
;
long
amount
;
int
err
;
BT_DBG
(
"sk %p cmd %x arg %lx"
,
sk
,
cmd
,
arg
);
switch
(
cmd
)
{
case
TIOCOUTQ
:
if
(
sk
->
sk_state
==
BT_LISTEN
)
return
-
EINVAL
;
amount
=
sk
->
sk_sndbuf
-
atomic_read
(
&
sk
->
sk_wmem_alloc
);
if
(
amount
<
0
)
amount
=
0
;
err
=
put_user
(
amount
,
(
int
__user
*
)
arg
);
break
;
case
TIOCINQ
:
if
(
sk
->
sk_state
==
BT_LISTEN
)
return
-
EINVAL
;
lock_sock
(
sk
);
skb
=
skb_peek
(
&
sk
->
sk_receive_queue
);
amount
=
skb
?
skb
->
len
:
0
;
release_sock
(
sk
);
err
=
put_user
(
amount
,
(
int
__user
*
)
arg
);
break
;
case
SIOCGSTAMP
:
err
=
sock_get_timestamp
(
sk
,
(
struct
timeval
__user
*
)
arg
);
break
;
case
SIOCGSTAMPNS
:
err
=
sock_get_timestampns
(
sk
,
(
struct
timespec
__user
*
)
arg
);
break
;
default:
err
=
-
ENOIOCTLCMD
;
break
;
}
return
err
;
}
EXPORT_SYMBOL
(
bt_sock_ioctl
);
int
bt_sock_wait_state
(
struct
sock
*
sk
,
int
state
,
unsigned
long
timeo
)
int
bt_sock_wait_state
(
struct
sock
*
sk
,
int
state
,
unsigned
long
timeo
)
{
{
DECLARE_WAITQUEUE
(
wait
,
current
);
DECLARE_WAITQUEUE
(
wait
,
current
);
...
...
net/bluetooth/bnep/core.c
View file @
407d819c
...
@@ -503,6 +503,11 @@ static int bnep_session(void *arg)
...
@@ -503,6 +503,11 @@ static int bnep_session(void *arg)
/* Delete network device */
/* Delete network device */
unregister_netdev
(
dev
);
unregister_netdev
(
dev
);
/* Wakeup user-space polling for socket errors */
s
->
sock
->
sk
->
sk_err
=
EUNATCH
;
wake_up_interruptible
(
s
->
sock
->
sk
->
sk_sleep
);
/* Release the socket */
/* Release the socket */
fput
(
s
->
sock
->
file
);
fput
(
s
->
sock
->
file
);
...
...
net/bluetooth/hci_conn.c
View file @
407d819c
...
@@ -59,24 +59,31 @@ void hci_acl_connect(struct hci_conn *conn)
...
@@ -59,24 +59,31 @@ void hci_acl_connect(struct hci_conn *conn)
BT_DBG
(
"%p"
,
conn
);
BT_DBG
(
"%p"
,
conn
);
conn
->
state
=
BT_CONNECT
;
conn
->
state
=
BT_CONNECT
;
conn
->
out
=
1
;
conn
->
out
=
1
;
conn
->
link_mode
=
HCI_LM_MASTER
;
conn
->
link_mode
=
HCI_LM_MASTER
;
conn
->
attempt
++
;
conn
->
attempt
++
;
conn
->
link_policy
=
hdev
->
link_policy
;
memset
(
&
cp
,
0
,
sizeof
(
cp
));
memset
(
&
cp
,
0
,
sizeof
(
cp
));
bacpy
(
&
cp
.
bdaddr
,
&
conn
->
dst
);
bacpy
(
&
cp
.
bdaddr
,
&
conn
->
dst
);
cp
.
pscan_rep_mode
=
0x02
;
cp
.
pscan_rep_mode
=
0x02
;
if
((
ie
=
hci_inquiry_cache_lookup
(
hdev
,
&
conn
->
dst
))
&&
if
((
ie
=
hci_inquiry_cache_lookup
(
hdev
,
&
conn
->
dst
)))
{
inquiry_entry_age
(
ie
)
<=
INQUIRY_ENTRY_AGE_MAX
)
{
if
(
inquiry_entry_age
(
ie
)
<=
INQUIRY_ENTRY_AGE_MAX
)
{
cp
.
pscan_rep_mode
=
ie
->
data
.
pscan_rep_mode
;
cp
.
pscan_rep_mode
=
ie
->
data
.
pscan_rep_mode
;
cp
.
pscan_mode
=
ie
->
data
.
pscan_mode
;
cp
.
pscan_mode
=
ie
->
data
.
pscan_mode
;
cp
.
clock_offset
=
ie
->
data
.
clock_offset
|
cpu_to_le16
(
0x8000
);
cp
.
clock_offset
=
ie
->
data
.
clock_offset
|
cpu_to_le16
(
0x8000
);
}
memcpy
(
conn
->
dev_class
,
ie
->
data
.
dev_class
,
3
);
memcpy
(
conn
->
dev_class
,
ie
->
data
.
dev_class
,
3
);
conn
->
ssp_mode
=
ie
->
data
.
ssp_mode
;
}
}
cp
.
pkt_type
=
cpu_to_le16
(
hdev
->
pkt_type
&
ACL_PTYPE_MASK
);
cp
.
pkt_type
=
cpu_to_le16
(
conn
->
pkt_type
);
if
(
lmp_rswitch_capable
(
hdev
)
&&
!
(
hdev
->
link_mode
&
HCI_LM_MASTER
))
if
(
lmp_rswitch_capable
(
hdev
)
&&
!
(
hdev
->
link_mode
&
HCI_LM_MASTER
))
cp
.
role_switch
=
0x01
;
cp
.
role_switch
=
0x01
;
else
else
...
@@ -122,7 +129,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
...
@@ -122,7 +129,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
conn
->
out
=
1
;
conn
->
out
=
1
;
cp
.
handle
=
cpu_to_le16
(
handle
);
cp
.
handle
=
cpu_to_le16
(
handle
);
cp
.
pkt_type
=
cpu_to_le16
(
hdev
->
pkt_type
&
SCO_PTYPE_MASK
);
cp
.
pkt_type
=
cpu_to_le16
(
conn
->
pkt_type
);
hci_send_cmd
(
hdev
,
HCI_OP_ADD_SCO
,
sizeof
(
cp
),
&
cp
);
hci_send_cmd
(
hdev
,
HCI_OP_ADD_SCO
,
sizeof
(
cp
),
&
cp
);
}
}
...
@@ -138,7 +145,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
...
@@ -138,7 +145,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
conn
->
out
=
1
;
conn
->
out
=
1
;
cp
.
handle
=
cpu_to_le16
(
handle
);
cp
.
handle
=
cpu_to_le16
(
handle
);
cp
.
pkt_type
=
cpu_to_le16
(
hdev
->
esco
_type
);
cp
.
pkt_type
=
cpu_to_le16
(
conn
->
pkt
_type
);
cp
.
tx_bandwidth
=
cpu_to_le32
(
0x00001f40
);
cp
.
tx_bandwidth
=
cpu_to_le32
(
0x00001f40
);
cp
.
rx_bandwidth
=
cpu_to_le32
(
0x00001f40
);
cp
.
rx_bandwidth
=
cpu_to_le32
(
0x00001f40
);
...
@@ -163,11 +170,13 @@ static void hci_conn_timeout(unsigned long arg)
...
@@ -163,11 +170,13 @@ static void hci_conn_timeout(unsigned long arg)
switch
(
conn
->
state
)
{
switch
(
conn
->
state
)
{
case
BT_CONNECT
:
case
BT_CONNECT
:
case
BT_CONNECT2
:
if
(
conn
->
type
==
ACL_LINK
)
if
(
conn
->
type
==
ACL_LINK
)
hci_acl_connect_cancel
(
conn
);
hci_acl_connect_cancel
(
conn
);
else
else
hci_acl_disconn
(
conn
,
0x13
);
hci_acl_disconn
(
conn
,
0x13
);
break
;
break
;
case
BT_CONFIG
:
case
BT_CONNECTED
:
case
BT_CONNECTED
:
hci_acl_disconn
(
conn
,
0x13
);
hci_acl_disconn
(
conn
,
0x13
);
break
;
break
;
...
@@ -199,13 +208,28 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
...
@@ -199,13 +208,28 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
return
NULL
;
return
NULL
;
bacpy
(
&
conn
->
dst
,
dst
);
bacpy
(
&
conn
->
dst
,
dst
);
conn
->
hdev
=
hdev
;
conn
->
hdev
=
hdev
;
conn
->
type
=
type
;
conn
->
type
=
type
;
conn
->
mode
=
HCI_CM_ACTIVE
;
conn
->
mode
=
HCI_CM_ACTIVE
;
conn
->
state
=
BT_OPEN
;
conn
->
state
=
BT_OPEN
;
conn
->
power_save
=
1
;
conn
->
power_save
=
1
;
switch
(
type
)
{
case
ACL_LINK
:
conn
->
pkt_type
=
hdev
->
pkt_type
&
ACL_PTYPE_MASK
;
break
;
case
SCO_LINK
:
if
(
lmp_esco_capable
(
hdev
))
conn
->
pkt_type
=
hdev
->
esco_type
&
SCO_ESCO_MASK
;
else
conn
->
pkt_type
=
hdev
->
pkt_type
&
SCO_PTYPE_MASK
;
break
;
case
ESCO_LINK
:
conn
->
pkt_type
=
hdev
->
esco_type
;
break
;
}
skb_queue_head_init
(
&
conn
->
data_q
);
skb_queue_head_init
(
&
conn
->
data_q
);
setup_timer
(
&
conn
->
disc_timer
,
hci_conn_timeout
,
(
unsigned
long
)
conn
);
setup_timer
(
&
conn
->
disc_timer
,
hci_conn_timeout
,
(
unsigned
long
)
conn
);
...
@@ -221,8 +245,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
...
@@ -221,8 +245,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
if
(
hdev
->
notify
)
if
(
hdev
->
notify
)
hdev
->
notify
(
hdev
,
HCI_NOTIFY_CONN_ADD
);
hdev
->
notify
(
hdev
,
HCI_NOTIFY_CONN_ADD
);
hci_conn_add_sysfs
(
conn
);
tasklet_enable
(
&
hdev
->
tx_task
);
tasklet_enable
(
&
hdev
->
tx_task
);
return
conn
;
return
conn
;
...
@@ -254,12 +276,14 @@ int hci_conn_del(struct hci_conn *conn)
...
@@ -254,12 +276,14 @@ int hci_conn_del(struct hci_conn *conn)
}
}
tasklet_disable
(
&
hdev
->
tx_task
);
tasklet_disable
(
&
hdev
->
tx_task
);
hci_conn_hash_del
(
hdev
,
conn
);
hci_conn_hash_del
(
hdev
,
conn
);
if
(
hdev
->
notify
)
if
(
hdev
->
notify
)
hdev
->
notify
(
hdev
,
HCI_NOTIFY_CONN_DEL
);
hdev
->
notify
(
hdev
,
HCI_NOTIFY_CONN_DEL
);
tasklet_enable
(
&
hdev
->
tx_task
);
tasklet_enable
(
&
hdev
->
tx_task
);
skb_queue_purge
(
&
conn
->
data_q
);
skb_queue_purge
(
&
conn
->
data_q
);
hci_conn_del_sysfs
(
conn
);
return
0
;
return
0
;
}
}
...
@@ -355,13 +379,21 @@ int hci_conn_auth(struct hci_conn *conn)
...
@@ -355,13 +379,21 @@ int hci_conn_auth(struct hci_conn *conn)
{
{
BT_DBG
(
"conn %p"
,
conn
);
BT_DBG
(
"conn %p"
,
conn
);
if
(
conn
->
ssp_mode
>
0
&&
conn
->
hdev
->
ssp_mode
>
0
)
{
if
(
!
(
conn
->
auth_type
&
0x01
))
{
conn
->
auth_type
=
HCI_AT_GENERAL_BONDING_MITM
;
conn
->
link_mode
&=
~
HCI_LM_AUTH
;
}
}
if
(
conn
->
link_mode
&
HCI_LM_AUTH
)
if
(
conn
->
link_mode
&
HCI_LM_AUTH
)
return
1
;
return
1
;
if
(
!
test_and_set_bit
(
HCI_CONN_AUTH_PEND
,
&
conn
->
pend
))
{
if
(
!
test_and_set_bit
(
HCI_CONN_AUTH_PEND
,
&
conn
->
pend
))
{
struct
hci_cp_auth_requested
cp
;
struct
hci_cp_auth_requested
cp
;
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
hci_send_cmd
(
conn
->
hdev
,
HCI_OP_AUTH_REQUESTED
,
sizeof
(
cp
),
&
cp
);
hci_send_cmd
(
conn
->
hdev
,
HCI_OP_AUTH_REQUESTED
,
sizeof
(
cp
),
&
cp
);
}
}
return
0
;
return
0
;
}
}
...
@@ -373,7 +405,7 @@ int hci_conn_encrypt(struct hci_conn *conn)
...
@@ -373,7 +405,7 @@ int hci_conn_encrypt(struct hci_conn *conn)
BT_DBG
(
"conn %p"
,
conn
);
BT_DBG
(
"conn %p"
,
conn
);
if
(
conn
->
link_mode
&
HCI_LM_ENCRYPT
)
if
(
conn
->
link_mode
&
HCI_LM_ENCRYPT
)
return
1
;
return
hci_conn_auth
(
conn
)
;
if
(
test_and_set_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
pend
))
if
(
test_and_set_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
pend
))
return
0
;
return
0
;
...
@@ -382,7 +414,8 @@ int hci_conn_encrypt(struct hci_conn *conn)
...
@@ -382,7 +414,8 @@ int hci_conn_encrypt(struct hci_conn *conn)
struct
hci_cp_set_conn_encrypt
cp
;
struct
hci_cp_set_conn_encrypt
cp
;
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
cp
.
encrypt
=
1
;
cp
.
encrypt
=
1
;
hci_send_cmd
(
conn
->
hdev
,
HCI_OP_SET_CONN_ENCRYPT
,
sizeof
(
cp
),
&
cp
);
hci_send_cmd
(
conn
->
hdev
,
HCI_OP_SET_CONN_ENCRYPT
,
sizeof
(
cp
),
&
cp
);
}
}
return
0
;
return
0
;
}
}
...
@@ -396,7 +429,8 @@ int hci_conn_change_link_key(struct hci_conn *conn)
...
@@ -396,7 +429,8 @@ int hci_conn_change_link_key(struct hci_conn *conn)
if
(
!
test_and_set_bit
(
HCI_CONN_AUTH_PEND
,
&
conn
->
pend
))
{
if
(
!
test_and_set_bit
(
HCI_CONN_AUTH_PEND
,
&
conn
->
pend
))
{
struct
hci_cp_change_conn_link_key
cp
;
struct
hci_cp_change_conn_link_key
cp
;
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
hci_send_cmd
(
conn
->
hdev
,
HCI_OP_CHANGE_CONN_LINK_KEY
,
sizeof
(
cp
),
&
cp
);
hci_send_cmd
(
conn
->
hdev
,
HCI_OP_CHANGE_CONN_LINK_KEY
,
sizeof
(
cp
),
&
cp
);
}
}
return
0
;
return
0
;
}
}
...
@@ -498,6 +532,8 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
...
@@ -498,6 +532,8 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
c
->
state
=
BT_CLOSED
;
c
->
state
=
BT_CLOSED
;
hci_conn_del_sysfs
(
c
);
hci_proto_disconn_ind
(
c
,
0x16
);
hci_proto_disconn_ind
(
c
,
0x16
);
hci_conn_del
(
c
);
hci_conn_del
(
c
);
}
}
...
@@ -600,3 +636,23 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
...
@@ -600,3 +636,23 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
return
copy_to_user
(
ptr
,
&
ci
,
sizeof
(
ci
))
?
-
EFAULT
:
0
;
return
copy_to_user
(
ptr
,
&
ci
,
sizeof
(
ci
))
?
-
EFAULT
:
0
;
}
}
int
hci_get_auth_info
(
struct
hci_dev
*
hdev
,
void
__user
*
arg
)
{
struct
hci_auth_info_req
req
;
struct
hci_conn
*
conn
;
if
(
copy_from_user
(
&
req
,
arg
,
sizeof
(
req
)))
return
-
EFAULT
;
hci_dev_lock_bh
(
hdev
);
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
ACL_LINK
,
&
req
.
bdaddr
);
if
(
conn
)
req
.
type
=
conn
->
auth_type
;
hci_dev_unlock_bh
(
hdev
);
if
(
!
conn
)
return
-
ENOENT
;
return
copy_to_user
(
arg
,
&
req
,
sizeof
(
req
))
?
-
EFAULT
:
0
;
}
net/bluetooth/hci_core.c
View file @
407d819c
...
@@ -279,10 +279,20 @@ static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
...
@@ -279,10 +279,20 @@ static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
BT_DBG
(
"%s %x"
,
hdev
->
name
,
encrypt
);
BT_DBG
(
"%s %x"
,
hdev
->
name
,
encrypt
);
/*
Authentica
tion */
/*
Encryp
tion */
hci_send_cmd
(
hdev
,
HCI_OP_WRITE_ENCRYPT_MODE
,
1
,
&
encrypt
);
hci_send_cmd
(
hdev
,
HCI_OP_WRITE_ENCRYPT_MODE
,
1
,
&
encrypt
);
}
}
static
void
hci_linkpol_req
(
struct
hci_dev
*
hdev
,
unsigned
long
opt
)
{
__le16
policy
=
cpu_to_le16
(
opt
);
BT_DBG
(
"%s %x"
,
hdev
->
name
,
opt
);
/* Default link policy */
hci_send_cmd
(
hdev
,
HCI_OP_WRITE_DEF_LINK_POLICY
,
2
,
&
policy
);
}
/* Get HCI device by index.
/* Get HCI device by index.
* Device is held on return. */
* Device is held on return. */
struct
hci_dev
*
hci_dev_get
(
int
index
)
struct
hci_dev
*
hci_dev_get
(
int
index
)
...
@@ -694,32 +704,35 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
...
@@ -694,32 +704,35 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
msecs_to_jiffies
(
HCI_INIT_TIMEOUT
));
msecs_to_jiffies
(
HCI_INIT_TIMEOUT
));
break
;
break
;
case
HCISETPTYPE
:
hdev
->
pkt_type
=
(
__u16
)
dr
.
dev_opt
;
break
;
case
HCISETLINKPOL
:
case
HCISETLINKPOL
:
hdev
->
link_policy
=
(
__u16
)
dr
.
dev_opt
;
err
=
hci_request
(
hdev
,
hci_linkpol_req
,
dr
.
dev_opt
,
msecs_to_jiffies
(
HCI_INIT_TIMEOUT
));
break
;
break
;
case
HCISETLINKMODE
:
case
HCISETLINKMODE
:
hdev
->
link_mode
=
((
__u16
)
dr
.
dev_opt
)
&
(
HCI_LM_MASTER
|
HCI_LM_ACCEPT
);
hdev
->
link_mode
=
((
__u16
)
dr
.
dev_opt
)
&
(
HCI_LM_MASTER
|
HCI_LM_ACCEPT
);
break
;
case
HCISETPTYPE
:
hdev
->
pkt_type
=
(
__u16
)
dr
.
dev_opt
;
break
;
break
;
case
HCISETACLMTU
:
case
HCISETACLMTU
:
hdev
->
acl_mtu
=
*
((
__u16
*
)
&
dr
.
dev_opt
+
1
);
hdev
->
acl_mtu
=
*
((
__u16
*
)
&
dr
.
dev_opt
+
1
);
hdev
->
acl_pkts
=
*
((
__u16
*
)
&
dr
.
dev_opt
+
0
);
hdev
->
acl_pkts
=
*
((
__u16
*
)
&
dr
.
dev_opt
+
0
);
break
;
break
;
case
HCISETSCOMTU
:
case
HCISETSCOMTU
:
hdev
->
sco_mtu
=
*
((
__u16
*
)
&
dr
.
dev_opt
+
1
);
hdev
->
sco_mtu
=
*
((
__u16
*
)
&
dr
.
dev_opt
+
1
);
hdev
->
sco_pkts
=
*
((
__u16
*
)
&
dr
.
dev_opt
+
0
);
hdev
->
sco_pkts
=
*
((
__u16
*
)
&
dr
.
dev_opt
+
0
);
break
;
break
;
default:
default:
err
=
-
EINVAL
;
err
=
-
EINVAL
;
break
;
break
;
}
}
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
}
}
...
@@ -1270,9 +1283,12 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
...
@@ -1270,9 +1283,12 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
struct
hci_conn
*
c
;
struct
hci_conn
*
c
;
c
=
list_entry
(
p
,
struct
hci_conn
,
list
);
c
=
list_entry
(
p
,
struct
hci_conn
,
list
);
if
(
c
->
type
!=
type
||
c
->
state
!=
BT_CONNECTED
if
(
c
->
type
!=
type
||
skb_queue_empty
(
&
c
->
data_q
))
||
skb_queue_empty
(
&
c
->
data_q
))
continue
;
if
(
c
->
state
!=
BT_CONNECTED
&&
c
->
state
!=
BT_CONFIG
)
continue
;
continue
;
num
++
;
num
++
;
if
(
c
->
sent
<
min
)
{
if
(
c
->
sent
<
min
)
{
...
...
net/bluetooth/hci_event.c
View file @
407d819c
...
@@ -110,6 +110,25 @@ static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -110,6 +110,25 @@ static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_unlock
(
hdev
);
hci_dev_unlock
(
hdev
);
}
}
static
void
hci_cc_read_link_policy
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_rp_read_link_policy
*
rp
=
(
void
*
)
skb
->
data
;
struct
hci_conn
*
conn
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
rp
->
status
);
if
(
rp
->
status
)
return
;
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
rp
->
handle
));
if
(
conn
)
conn
->
link_policy
=
__le16_to_cpu
(
rp
->
policy
);
hci_dev_unlock
(
hdev
);
}
static
void
hci_cc_write_link_policy
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
static
void
hci_cc_write_link_policy
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
{
struct
hci_rp_write_link_policy
*
rp
=
(
void
*
)
skb
->
data
;
struct
hci_rp_write_link_policy
*
rp
=
(
void
*
)
skb
->
data
;
...
@@ -128,13 +147,41 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -128,13 +147,41 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_lock
(
hdev
);
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
rp
->
handle
));
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
rp
->
handle
));
if
(
conn
)
{
if
(
conn
)
conn
->
link_policy
=
get_unaligned_le16
(
sent
+
2
);
conn
->
link_policy
=
get_unaligned_le16
(
sent
+
2
);
}
hci_dev_unlock
(
hdev
);
hci_dev_unlock
(
hdev
);
}
}
static
void
hci_cc_read_def_link_policy
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_rp_read_def_link_policy
*
rp
=
(
void
*
)
skb
->
data
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
rp
->
status
);
if
(
rp
->
status
)
return
;
hdev
->
link_policy
=
__le16_to_cpu
(
rp
->
policy
);
}
static
void
hci_cc_write_def_link_policy
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
__u8
status
=
*
((
__u8
*
)
skb
->
data
);
void
*
sent
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
sent
=
hci_sent_cmd_data
(
hdev
,
HCI_OP_WRITE_DEF_LINK_POLICY
);
if
(
!
sent
)
return
;
if
(
!
status
)
hdev
->
link_policy
=
get_unaligned_le16
(
sent
);
hci_req_complete
(
hdev
,
status
);
}
static
void
hci_cc_reset
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
static
void
hci_cc_reset
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
{
__u8
status
=
*
((
__u8
*
)
skb
->
data
);
__u8
status
=
*
((
__u8
*
)
skb
->
data
);
...
@@ -151,12 +198,14 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -151,12 +198,14 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
if
(
status
)
return
;
sent
=
hci_sent_cmd_data
(
hdev
,
HCI_OP_WRITE_LOCAL_NAME
);
sent
=
hci_sent_cmd_data
(
hdev
,
HCI_OP_WRITE_LOCAL_NAME
);
if
(
!
sent
)
if
(
!
sent
)
return
;
return
;
if
(
!
status
)
memcpy
(
hdev
->
dev_name
,
sent
,
248
);
memcpy
(
hdev
->
dev_name
,
sent
,
248
);
}
}
static
void
hci_cc_read_local_name
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
static
void
hci_cc_read_local_name
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
@@ -266,12 +315,14 @@ static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -266,12 +315,14 @@ static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
if
(
status
)
return
;
sent
=
hci_sent_cmd_data
(
hdev
,
HCI_OP_WRITE_CLASS_OF_DEV
);
sent
=
hci_sent_cmd_data
(
hdev
,
HCI_OP_WRITE_CLASS_OF_DEV
);
if
(
!
sent
)
if
(
!
sent
)
return
;
return
;
if
(
!
status
)
memcpy
(
hdev
->
dev_class
,
sent
,
3
);
memcpy
(
hdev
->
dev_class
,
sent
,
3
);
}
}
static
void
hci_cc_read_voice_setting
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
static
void
hci_cc_read_voice_setting
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
@@ -286,7 +337,7 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -286,7 +337,7 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
setting
=
__le16_to_cpu
(
rp
->
voice_setting
);
setting
=
__le16_to_cpu
(
rp
->
voice_setting
);
if
(
hdev
->
voice_setting
==
setting
)
if
(
hdev
->
voice_setting
==
setting
)
return
;
return
;
hdev
->
voice_setting
=
setting
;
hdev
->
voice_setting
=
setting
;
...
@@ -303,28 +354,31 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -303,28 +354,31 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
static
void
hci_cc_write_voice_setting
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
static
void
hci_cc_write_voice_setting
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
{
__u8
status
=
*
((
__u8
*
)
skb
->
data
);
__u8
status
=
*
((
__u8
*
)
skb
->
data
);
__u16
setting
;
void
*
sent
;
void
*
sent
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
if
(
status
)
return
;
sent
=
hci_sent_cmd_data
(
hdev
,
HCI_OP_WRITE_VOICE_SETTING
);
sent
=
hci_sent_cmd_data
(
hdev
,
HCI_OP_WRITE_VOICE_SETTING
);
if
(
!
sent
)
if
(
!
sent
)
return
;
return
;
if
(
!
status
)
{
setting
=
get_unaligned_le16
(
sent
);
__u16
setting
=
get_unaligned_le16
(
sent
);
if
(
hdev
->
voice_setting
!=
setting
)
{
if
(
hdev
->
voice_setting
==
setting
)
hdev
->
voice_setting
=
setting
;
return
;
BT_DBG
(
"%s voice setting 0x%04x"
,
hdev
->
name
,
setting
)
;
hdev
->
voice_setting
=
setting
;
if
(
hdev
->
notify
)
{
BT_DBG
(
"%s voice setting 0x%04x"
,
hdev
->
name
,
setting
);
tasklet_disable
(
&
hdev
->
tx_task
);
hdev
->
notify
(
hdev
,
HCI_NOTIFY_VOICE_SETTING
);
if
(
hdev
->
notify
)
{
tasklet_en
able
(
&
hdev
->
tx_task
);
tasklet_dis
able
(
&
hdev
->
tx_task
);
}
hdev
->
notify
(
hdev
,
HCI_NOTIFY_VOICE_SETTING
);
}
tasklet_enable
(
&
hdev
->
tx_task
);
}
}
}
}
...
@@ -337,6 +391,35 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -337,6 +391,35 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
hci_req_complete
(
hdev
,
status
);
hci_req_complete
(
hdev
,
status
);
}
}
static
void
hci_cc_read_ssp_mode
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_rp_read_ssp_mode
*
rp
=
(
void
*
)
skb
->
data
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
rp
->
status
);
if
(
rp
->
status
)
return
;
hdev
->
ssp_mode
=
rp
->
mode
;
}
static
void
hci_cc_write_ssp_mode
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
__u8
status
=
*
((
__u8
*
)
skb
->
data
);
void
*
sent
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
if
(
status
)
return
;
sent
=
hci_sent_cmd_data
(
hdev
,
HCI_OP_WRITE_SSP_MODE
);
if
(
!
sent
)
return
;
hdev
->
ssp_mode
=
*
((
__u8
*
)
sent
);
}
static
void
hci_cc_read_local_version
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
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
;
struct
hci_rp_read_local_version
*
rp
=
(
void
*
)
skb
->
data
;
...
@@ -347,8 +430,8 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -347,8 +430,8 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
return
;
return
;
hdev
->
hci_ver
=
rp
->
hci_ver
;
hdev
->
hci_ver
=
rp
->
hci_ver
;
hdev
->
hci_rev
=
btohs
(
rp
->
hci_rev
);
hdev
->
hci_rev
=
__le16_to_cpu
(
rp
->
hci_rev
);
hdev
->
manufacturer
=
btohs
(
rp
->
manufacturer
);
hdev
->
manufacturer
=
__le16_to_cpu
(
rp
->
manufacturer
);
BT_DBG
(
"%s manufacturer %d hci ver %d:%d"
,
hdev
->
name
,
BT_DBG
(
"%s manufacturer %d hci ver %d:%d"
,
hdev
->
name
,
hdev
->
manufacturer
,
hdev
->
manufacturer
,
...
@@ -536,11 +619,119 @@ static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status)
...
@@ -536,11 +619,119 @@ static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status)
hci_dev_unlock
(
hdev
);
hci_dev_unlock
(
hdev
);
}
}
static
void
hci_cs_auth_requested
(
struct
hci_dev
*
hdev
,
__u8
status
)
{
struct
hci_cp_auth_requested
*
cp
;
struct
hci_conn
*
conn
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
if
(
!
status
)
return
;
cp
=
hci_sent_cmd_data
(
hdev
,
HCI_OP_AUTH_REQUESTED
);
if
(
!
cp
)
return
;
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
cp
->
handle
));
if
(
conn
)
{
if
(
conn
->
state
==
BT_CONFIG
)
{
hci_proto_connect_cfm
(
conn
,
status
);
hci_conn_put
(
conn
);
}
}
hci_dev_unlock
(
hdev
);
}
static
void
hci_cs_set_conn_encrypt
(
struct
hci_dev
*
hdev
,
__u8
status
)
{
struct
hci_cp_set_conn_encrypt
*
cp
;
struct
hci_conn
*
conn
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
if
(
!
status
)
return
;
cp
=
hci_sent_cmd_data
(
hdev
,
HCI_OP_SET_CONN_ENCRYPT
);
if
(
!
cp
)
return
;
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
cp
->
handle
));
if
(
conn
)
{
if
(
conn
->
state
==
BT_CONFIG
)
{
hci_proto_connect_cfm
(
conn
,
status
);
hci_conn_put
(
conn
);
}
}
hci_dev_unlock
(
hdev
);
}
static
void
hci_cs_remote_name_req
(
struct
hci_dev
*
hdev
,
__u8
status
)
static
void
hci_cs_remote_name_req
(
struct
hci_dev
*
hdev
,
__u8
status
)
{
{
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
}
}
static
void
hci_cs_read_remote_features
(
struct
hci_dev
*
hdev
,
__u8
status
)
{
struct
hci_cp_read_remote_features
*
cp
;
struct
hci_conn
*
conn
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
if
(
!
status
)
return
;
cp
=
hci_sent_cmd_data
(
hdev
,
HCI_OP_READ_REMOTE_FEATURES
);
if
(
!
cp
)
return
;
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
cp
->
handle
));
if
(
conn
)
{
if
(
conn
->
state
==
BT_CONFIG
)
{
hci_proto_connect_cfm
(
conn
,
status
);
hci_conn_put
(
conn
);
}
}
hci_dev_unlock
(
hdev
);
}
static
void
hci_cs_read_remote_ext_features
(
struct
hci_dev
*
hdev
,
__u8
status
)
{
struct
hci_cp_read_remote_ext_features
*
cp
;
struct
hci_conn
*
conn
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
status
);
if
(
!
status
)
return
;
cp
=
hci_sent_cmd_data
(
hdev
,
HCI_OP_READ_REMOTE_EXT_FEATURES
);
if
(
!
cp
)
return
;
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
cp
->
handle
));
if
(
conn
)
{
if
(
conn
->
state
==
BT_CONFIG
)
{
hci_proto_connect_cfm
(
conn
,
status
);
hci_conn_put
(
conn
);
}
}
hci_dev_unlock
(
hdev
);
}
static
void
hci_cs_setup_sync_conn
(
struct
hci_dev
*
hdev
,
__u8
status
)
static
void
hci_cs_setup_sync_conn
(
struct
hci_dev
*
hdev
,
__u8
status
)
{
{
struct
hci_cp_setup_sync_conn
*
cp
;
struct
hci_cp_setup_sync_conn
*
cp
;
...
@@ -653,6 +844,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
...
@@ -653,6 +844,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
memcpy
(
data
.
dev_class
,
info
->
dev_class
,
3
);
memcpy
(
data
.
dev_class
,
info
->
dev_class
,
3
);
data
.
clock_offset
=
info
->
clock_offset
;
data
.
clock_offset
=
info
->
clock_offset
;
data
.
rssi
=
0x00
;
data
.
rssi
=
0x00
;
data
.
ssp_mode
=
0x00
;
info
++
;
info
++
;
hci_inquiry_cache_update
(
hdev
,
&
data
);
hci_inquiry_cache_update
(
hdev
,
&
data
);
}
}
...
@@ -675,7 +867,14 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
...
@@ -675,7 +867,14 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
if
(
!
ev
->
status
)
{
if
(
!
ev
->
status
)
{
conn
->
handle
=
__le16_to_cpu
(
ev
->
handle
);
conn
->
handle
=
__le16_to_cpu
(
ev
->
handle
);
conn
->
state
=
BT_CONNECTED
;
if
(
conn
->
type
==
ACL_LINK
)
{
conn
->
state
=
BT_CONFIG
;
hci_conn_hold
(
conn
);
}
else
conn
->
state
=
BT_CONNECTED
;
hci_conn_add_sysfs
(
conn
);
if
(
test_bit
(
HCI_AUTH
,
&
hdev
->
flags
))
if
(
test_bit
(
HCI_AUTH
,
&
hdev
->
flags
))
conn
->
link_mode
|=
HCI_LM_AUTH
;
conn
->
link_mode
|=
HCI_LM_AUTH
;
...
@@ -687,30 +886,17 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
...
@@ -687,30 +886,17 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
if
(
conn
->
type
==
ACL_LINK
)
{
if
(
conn
->
type
==
ACL_LINK
)
{
struct
hci_cp_read_remote_features
cp
;
struct
hci_cp_read_remote_features
cp
;
cp
.
handle
=
ev
->
handle
;
cp
.
handle
=
ev
->
handle
;
hci_send_cmd
(
hdev
,
HCI_OP_READ_REMOTE_FEATURES
,
sizeof
(
cp
),
&
cp
);
hci_send_cmd
(
hdev
,
HCI_OP_READ_REMOTE_FEATURES
,
}
sizeof
(
cp
),
&
cp
);
/* Set link policy */
if
(
conn
->
type
==
ACL_LINK
&&
hdev
->
link_policy
)
{
struct
hci_cp_write_link_policy
cp
;
cp
.
handle
=
ev
->
handle
;
cp
.
policy
=
cpu_to_le16
(
hdev
->
link_policy
);
hci_send_cmd
(
hdev
,
HCI_OP_WRITE_LINK_POLICY
,
sizeof
(
cp
),
&
cp
);
}
}
/* Set packet type for incoming connection */
/* Set packet type for incoming connection */
if
(
!
conn
->
out
)
{
if
(
!
conn
->
out
&&
hdev
->
hci_ver
<
3
)
{
struct
hci_cp_change_conn_ptype
cp
;
struct
hci_cp_change_conn_ptype
cp
;
cp
.
handle
=
ev
->
handle
;
cp
.
handle
=
ev
->
handle
;
cp
.
pkt_type
=
(
conn
->
type
==
ACL_LINK
)
?
cp
.
pkt_type
=
cpu_to_le16
(
conn
->
pkt_type
);
cpu_to_le16
(
hdev
->
pkt_type
&
ACL_PTYPE_MASK
)
:
hci_send_cmd
(
hdev
,
HCI_OP_CHANGE_CONN_PTYPE
,
cpu_to_le16
(
hdev
->
pkt_type
&
SCO_PTYPE_MASK
);
sizeof
(
cp
),
&
cp
);
hci_send_cmd
(
hdev
,
HCI_OP_CHANGE_CONN_PTYPE
,
sizeof
(
cp
),
&
cp
);
}
else
{
/* Update disconnect timer */
hci_conn_hold
(
conn
);
hci_conn_put
(
conn
);
}
}
}
else
}
else
conn
->
state
=
BT_CLOSED
;
conn
->
state
=
BT_CLOSED
;
...
@@ -730,9 +916,10 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
...
@@ -730,9 +916,10 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
}
}
}
}
hci_proto_connect_cfm
(
conn
,
ev
->
status
);
if
(
ev
->
status
)
{
if
(
ev
->
status
)
hci_proto_connect_cfm
(
conn
,
ev
->
status
);
hci_conn_del
(
conn
);
hci_conn_del
(
conn
);
}
unlock:
unlock:
hci_dev_unlock
(
hdev
);
hci_dev_unlock
(
hdev
);
...
@@ -752,10 +939,14 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
...
@@ -752,10 +939,14 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
if
(
mask
&
HCI_LM_ACCEPT
)
{
if
(
mask
&
HCI_LM_ACCEPT
)
{
/* Connection accepted */
/* Connection accepted */
struct
inquiry_entry
*
ie
;
struct
hci_conn
*
conn
;
struct
hci_conn
*
conn
;
hci_dev_lock
(
hdev
);
hci_dev_lock
(
hdev
);
if
((
ie
=
hci_inquiry_cache_lookup
(
hdev
,
&
ev
->
bdaddr
)))
memcpy
(
ie
->
data
.
dev_class
,
ev
->
dev_class
,
3
);
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
ev
->
link_type
,
&
ev
->
bdaddr
);
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
ev
->
link_type
,
&
ev
->
bdaddr
);
if
(
!
conn
)
{
if
(
!
conn
)
{
if
(
!
(
conn
=
hci_conn_add
(
hdev
,
ev
->
link_type
,
&
ev
->
bdaddr
)))
{
if
(
!
(
conn
=
hci_conn_add
(
hdev
,
ev
->
link_type
,
&
ev
->
bdaddr
)))
{
...
@@ -786,7 +977,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
...
@@ -786,7 +977,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
struct
hci_cp_accept_sync_conn_req
cp
;
struct
hci_cp_accept_sync_conn_req
cp
;
bacpy
(
&
cp
.
bdaddr
,
&
ev
->
bdaddr
);
bacpy
(
&
cp
.
bdaddr
,
&
ev
->
bdaddr
);
cp
.
pkt_type
=
cpu_to_le16
(
hdev
->
esco
_type
);
cp
.
pkt_type
=
cpu_to_le16
(
conn
->
pkt
_type
);
cp
.
tx_bandwidth
=
cpu_to_le32
(
0x00001f40
);
cp
.
tx_bandwidth
=
cpu_to_le32
(
0x00001f40
);
cp
.
rx_bandwidth
=
cpu_to_le32
(
0x00001f40
);
cp
.
rx_bandwidth
=
cpu_to_le32
(
0x00001f40
);
...
@@ -822,6 +1013,9 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
...
@@ -822,6 +1013,9 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
ev
->
handle
));
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
ev
->
handle
));
if
(
conn
)
{
if
(
conn
)
{
conn
->
state
=
BT_CLOSED
;
conn
->
state
=
BT_CLOSED
;
hci_conn_del_sysfs
(
conn
);
hci_proto_disconn_ind
(
conn
,
ev
->
reason
);
hci_proto_disconn_ind
(
conn
,
ev
->
reason
);
hci_conn_del
(
conn
);
hci_conn_del
(
conn
);
}
}
...
@@ -845,15 +1039,29 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
...
@@ -845,15 +1039,29 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
clear_bit
(
HCI_CONN_AUTH_PEND
,
&
conn
->
pend
);
clear_bit
(
HCI_CONN_AUTH_PEND
,
&
conn
->
pend
);
hci_auth_cfm
(
conn
,
ev
->
status
);
if
(
conn
->
state
==
BT_CONFIG
)
{
if
(
!
ev
->
status
&&
hdev
->
ssp_mode
>
0
&&
conn
->
ssp_mode
>
0
)
{
struct
hci_cp_set_conn_encrypt
cp
;
cp
.
handle
=
ev
->
handle
;
cp
.
encrypt
=
0x01
;
hci_send_cmd
(
hdev
,
HCI_OP_SET_CONN_ENCRYPT
,
sizeof
(
cp
),
&
cp
);
}
else
{
conn
->
state
=
BT_CONNECTED
;
hci_proto_connect_cfm
(
conn
,
ev
->
status
);
hci_conn_put
(
conn
);
}
}
else
hci_auth_cfm
(
conn
,
ev
->
status
);
if
(
test_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
pend
))
{
if
(
test_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
pend
))
{
if
(
!
ev
->
status
)
{
if
(
!
ev
->
status
)
{
struct
hci_cp_set_conn_encrypt
cp
;
struct
hci_cp_set_conn_encrypt
cp
;
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
)
;
cp
.
handle
=
ev
->
handle
;
cp
.
encrypt
=
1
;
cp
.
encrypt
=
0x0
1
;
hci_send_cmd
(
conn
->
hdev
,
hci_send_cmd
(
hdev
,
HCI_OP_SET_CONN_ENCRYPT
,
HCI_OP_SET_CONN_ENCRYPT
,
sizeof
(
cp
),
&
cp
);
sizeof
(
cp
),
&
cp
);
}
else
{
}
else
{
clear_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
pend
);
clear_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
pend
);
hci_encrypt_cfm
(
conn
,
ev
->
status
,
0x00
);
hci_encrypt_cfm
(
conn
,
ev
->
status
,
0x00
);
...
@@ -883,15 +1091,24 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
...
@@ -883,15 +1091,24 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
ev
->
handle
));
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
ev
->
handle
));
if
(
conn
)
{
if
(
conn
)
{
if
(
!
ev
->
status
)
{
if
(
!
ev
->
status
)
{
if
(
ev
->
encrypt
)
if
(
ev
->
encrypt
)
{
/* Encryption implies authentication */
conn
->
link_mode
|=
HCI_LM_AUTH
;
conn
->
link_mode
|=
HCI_LM_ENCRYPT
;
conn
->
link_mode
|=
HCI_LM_ENCRYPT
;
else
}
else
conn
->
link_mode
&=
~
HCI_LM_ENCRYPT
;
conn
->
link_mode
&=
~
HCI_LM_ENCRYPT
;
}
}
clear_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
pend
);
clear_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
pend
);
hci_encrypt_cfm
(
conn
,
ev
->
status
,
ev
->
encrypt
);
if
(
conn
->
state
==
BT_CONFIG
)
{
if
(
!
ev
->
status
)
conn
->
state
=
BT_CONNECTED
;
hci_proto_connect_cfm
(
conn
,
ev
->
status
);
hci_conn_put
(
conn
);
}
else
hci_encrypt_cfm
(
conn
,
ev
->
status
,
ev
->
encrypt
);
}
}
hci_dev_unlock
(
hdev
);
hci_dev_unlock
(
hdev
);
...
@@ -926,14 +1143,29 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff
...
@@ -926,14 +1143,29 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff
BT_DBG
(
"%s status %d"
,
hdev
->
name
,
ev
->
status
);
BT_DBG
(
"%s status %d"
,
hdev
->
name
,
ev
->
status
);
if
(
ev
->
status
)
return
;
hci_dev_lock
(
hdev
);
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
ev
->
handle
));
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
ev
->
handle
));
if
(
conn
)
if
(
conn
)
{
memcpy
(
conn
->
features
,
ev
->
features
,
8
);
if
(
!
ev
->
status
)
memcpy
(
conn
->
features
,
ev
->
features
,
8
);
if
(
conn
->
state
==
BT_CONFIG
)
{
if
(
!
ev
->
status
&&
lmp_ssp_capable
(
hdev
)
&&
lmp_ssp_capable
(
conn
))
{
struct
hci_cp_read_remote_ext_features
cp
;
cp
.
handle
=
ev
->
handle
;
cp
.
page
=
0x01
;
hci_send_cmd
(
hdev
,
HCI_OP_READ_REMOTE_EXT_FEATURES
,
sizeof
(
cp
),
&
cp
);
}
else
{
conn
->
state
=
BT_CONNECTED
;
hci_proto_connect_cfm
(
conn
,
ev
->
status
);
hci_conn_put
(
conn
);
}
}
}
hci_dev_unlock
(
hdev
);
hci_dev_unlock
(
hdev
);
}
}
...
@@ -974,10 +1206,22 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
...
@@ -974,10 +1206,22 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_role_discovery
(
hdev
,
skb
);
hci_cc_role_discovery
(
hdev
,
skb
);
break
;
break
;
case
HCI_OP_READ_LINK_POLICY
:
hci_cc_read_link_policy
(
hdev
,
skb
);
break
;
case
HCI_OP_WRITE_LINK_POLICY
:
case
HCI_OP_WRITE_LINK_POLICY
:
hci_cc_write_link_policy
(
hdev
,
skb
);
hci_cc_write_link_policy
(
hdev
,
skb
);
break
;
break
;
case
HCI_OP_READ_DEF_LINK_POLICY
:
hci_cc_read_def_link_policy
(
hdev
,
skb
);
break
;
case
HCI_OP_WRITE_DEF_LINK_POLICY
:
hci_cc_write_def_link_policy
(
hdev
,
skb
);
break
;
case
HCI_OP_RESET
:
case
HCI_OP_RESET
:
hci_cc_reset
(
hdev
,
skb
);
hci_cc_reset
(
hdev
,
skb
);
break
;
break
;
...
@@ -1022,6 +1266,14 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
...
@@ -1022,6 +1266,14 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_host_buffer_size
(
hdev
,
skb
);
hci_cc_host_buffer_size
(
hdev
,
skb
);
break
;
break
;
case
HCI_OP_READ_SSP_MODE
:
hci_cc_read_ssp_mode
(
hdev
,
skb
);
break
;
case
HCI_OP_WRITE_SSP_MODE
:
hci_cc_write_ssp_mode
(
hdev
,
skb
);
break
;
case
HCI_OP_READ_LOCAL_VERSION
:
case
HCI_OP_READ_LOCAL_VERSION
:
hci_cc_read_local_version
(
hdev
,
skb
);
hci_cc_read_local_version
(
hdev
,
skb
);
break
;
break
;
...
@@ -1076,10 +1328,26 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -1076,10 +1328,26 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_add_sco
(
hdev
,
ev
->
status
);
hci_cs_add_sco
(
hdev
,
ev
->
status
);
break
;
break
;
case
HCI_OP_AUTH_REQUESTED
:
hci_cs_auth_requested
(
hdev
,
ev
->
status
);
break
;
case
HCI_OP_SET_CONN_ENCRYPT
:
hci_cs_set_conn_encrypt
(
hdev
,
ev
->
status
);
break
;
case
HCI_OP_REMOTE_NAME_REQ
:
case
HCI_OP_REMOTE_NAME_REQ
:
hci_cs_remote_name_req
(
hdev
,
ev
->
status
);
hci_cs_remote_name_req
(
hdev
,
ev
->
status
);
break
;
break
;
case
HCI_OP_READ_REMOTE_FEATURES
:
hci_cs_read_remote_features
(
hdev
,
ev
->
status
);
break
;
case
HCI_OP_READ_REMOTE_EXT_FEATURES
:
hci_cs_read_remote_ext_features
(
hdev
,
ev
->
status
);
break
;
case
HCI_OP_SETUP_SYNC_CONN
:
case
HCI_OP_SETUP_SYNC_CONN
:
hci_cs_setup_sync_conn
(
hdev
,
ev
->
status
);
hci_cs_setup_sync_conn
(
hdev
,
ev
->
status
);
break
;
break
;
...
@@ -1235,6 +1503,22 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
...
@@ -1235,6 +1503,22 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_dev_unlock
(
hdev
);
hci_dev_unlock
(
hdev
);
}
}
static
inline
void
hci_pkt_type_change_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_ev_pkt_type_change
*
ev
=
(
void
*
)
skb
->
data
;
struct
hci_conn
*
conn
;
BT_DBG
(
"%s status %d"
,
hdev
->
name
,
ev
->
status
);
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
ev
->
handle
));
if
(
conn
&&
!
ev
->
status
)
conn
->
pkt_type
=
__le16_to_cpu
(
ev
->
pkt_type
);
hci_dev_unlock
(
hdev
);
}
static
inline
void
hci_pscan_rep_mode_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
static
inline
void
hci_pscan_rep_mode_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
{
struct
hci_ev_pscan_rep_mode
*
ev
=
(
void
*
)
skb
->
data
;
struct
hci_ev_pscan_rep_mode
*
ev
=
(
void
*
)
skb
->
data
;
...
@@ -1275,6 +1559,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
...
@@ -1275,6 +1559,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
memcpy
(
data
.
dev_class
,
info
->
dev_class
,
3
);
memcpy
(
data
.
dev_class
,
info
->
dev_class
,
3
);
data
.
clock_offset
=
info
->
clock_offset
;
data
.
clock_offset
=
info
->
clock_offset
;
data
.
rssi
=
info
->
rssi
;
data
.
rssi
=
info
->
rssi
;
data
.
ssp_mode
=
0x00
;
info
++
;
info
++
;
hci_inquiry_cache_update
(
hdev
,
&
data
);
hci_inquiry_cache_update
(
hdev
,
&
data
);
}
}
...
@@ -1289,6 +1574,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
...
@@ -1289,6 +1574,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
memcpy
(
data
.
dev_class
,
info
->
dev_class
,
3
);
memcpy
(
data
.
dev_class
,
info
->
dev_class
,
3
);
data
.
clock_offset
=
info
->
clock_offset
;
data
.
clock_offset
=
info
->
clock_offset
;
data
.
rssi
=
info
->
rssi
;
data
.
rssi
=
info
->
rssi
;
data
.
ssp_mode
=
0x00
;
info
++
;
info
++
;
hci_inquiry_cache_update
(
hdev
,
&
data
);
hci_inquiry_cache_update
(
hdev
,
&
data
);
}
}
...
@@ -1299,7 +1585,43 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
...
@@ -1299,7 +1585,43 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
static
inline
void
hci_remote_ext_features_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
static
inline
void
hci_remote_ext_features_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
{
struct
hci_ev_remote_ext_features
*
ev
=
(
void
*
)
skb
->
data
;
struct
hci_conn
*
conn
;
BT_DBG
(
"%s"
,
hdev
->
name
);
BT_DBG
(
"%s"
,
hdev
->
name
);
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
__le16_to_cpu
(
ev
->
handle
));
if
(
conn
)
{
if
(
!
ev
->
status
&&
ev
->
page
==
0x01
)
{
struct
inquiry_entry
*
ie
;
if
((
ie
=
hci_inquiry_cache_lookup
(
hdev
,
&
conn
->
dst
)))
ie
->
data
.
ssp_mode
=
(
ev
->
features
[
0
]
&
0x01
);
conn
->
ssp_mode
=
(
ev
->
features
[
0
]
&
0x01
);
}
if
(
conn
->
state
==
BT_CONFIG
)
{
if
(
!
ev
->
status
&&
hdev
->
ssp_mode
>
0
&&
conn
->
ssp_mode
>
0
)
{
if
(
conn
->
out
)
{
struct
hci_cp_auth_requested
cp
;
cp
.
handle
=
ev
->
handle
;
hci_send_cmd
(
hdev
,
HCI_OP_AUTH_REQUESTED
,
sizeof
(
cp
),
&
cp
);
}
}
else
{
conn
->
state
=
BT_CONNECTED
;
hci_proto_connect_cfm
(
conn
,
ev
->
status
);
hci_conn_put
(
conn
);
}
}
}
hci_dev_unlock
(
hdev
);
}
}
static
inline
void
hci_sync_conn_complete_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
static
inline
void
hci_sync_conn_complete_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
@@ -1312,12 +1634,22 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu
...
@@ -1312,12 +1634,22 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu
hci_dev_lock
(
hdev
);
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
ev
->
link_type
,
&
ev
->
bdaddr
);
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
ev
->
link_type
,
&
ev
->
bdaddr
);
if
(
!
conn
)
if
(
!
conn
)
{
goto
unlock
;
if
(
ev
->
link_type
==
ESCO_LINK
)
goto
unlock
;
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
ESCO_LINK
,
&
ev
->
bdaddr
);
if
(
!
conn
)
goto
unlock
;
conn
->
type
=
SCO_LINK
;
}
if
(
!
ev
->
status
)
{
if
(
!
ev
->
status
)
{
conn
->
handle
=
__le16_to_cpu
(
ev
->
handle
);
conn
->
handle
=
__le16_to_cpu
(
ev
->
handle
);
conn
->
state
=
BT_CONNECTED
;
conn
->
state
=
BT_CONNECTED
;
hci_conn_add_sysfs
(
conn
);
}
else
}
else
conn
->
state
=
BT_CLOSED
;
conn
->
state
=
BT_CLOSED
;
...
@@ -1371,6 +1703,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
...
@@ -1371,6 +1703,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
memcpy
(
data
.
dev_class
,
info
->
dev_class
,
3
);
memcpy
(
data
.
dev_class
,
info
->
dev_class
,
3
);
data
.
clock_offset
=
info
->
clock_offset
;
data
.
clock_offset
=
info
->
clock_offset
;
data
.
rssi
=
info
->
rssi
;
data
.
rssi
=
info
->
rssi
;
data
.
ssp_mode
=
0x01
;
info
++
;
info
++
;
hci_inquiry_cache_update
(
hdev
,
&
data
);
hci_inquiry_cache_update
(
hdev
,
&
data
);
}
}
...
@@ -1378,6 +1711,53 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
...
@@ -1378,6 +1711,53 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
hci_dev_unlock
(
hdev
);
hci_dev_unlock
(
hdev
);
}
}
static
inline
void
hci_io_capa_request_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_ev_io_capa_request
*
ev
=
(
void
*
)
skb
->
data
;
struct
hci_conn
*
conn
;
BT_DBG
(
"%s"
,
hdev
->
name
);
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
ACL_LINK
,
&
ev
->
bdaddr
);
if
(
conn
)
hci_conn_hold
(
conn
);
hci_dev_unlock
(
hdev
);
}
static
inline
void
hci_simple_pair_complete_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_ev_simple_pair_complete
*
ev
=
(
void
*
)
skb
->
data
;
struct
hci_conn
*
conn
;
BT_DBG
(
"%s"
,
hdev
->
name
);
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
ACL_LINK
,
&
ev
->
bdaddr
);
if
(
conn
)
hci_conn_put
(
conn
);
hci_dev_unlock
(
hdev
);
}
static
inline
void
hci_remote_host_features_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_ev_remote_host_features
*
ev
=
(
void
*
)
skb
->
data
;
struct
inquiry_entry
*
ie
;
BT_DBG
(
"%s"
,
hdev
->
name
);
hci_dev_lock
(
hdev
);
if
((
ie
=
hci_inquiry_cache_lookup
(
hdev
,
&
ev
->
bdaddr
)))
ie
->
data
.
ssp_mode
=
(
ev
->
features
[
0
]
&
0x01
);
hci_dev_unlock
(
hdev
);
}
void
hci_event_packet
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
void
hci_event_packet
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
{
struct
hci_event_hdr
*
hdr
=
(
void
*
)
skb
->
data
;
struct
hci_event_hdr
*
hdr
=
(
void
*
)
skb
->
data
;
...
@@ -1470,6 +1850,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -1470,6 +1850,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_clock_offset_evt
(
hdev
,
skb
);
hci_clock_offset_evt
(
hdev
,
skb
);
break
;
break
;
case
HCI_EV_PKT_TYPE_CHANGE
:
hci_pkt_type_change_evt
(
hdev
,
skb
);
break
;
case
HCI_EV_PSCAN_REP_MODE
:
case
HCI_EV_PSCAN_REP_MODE
:
hci_pscan_rep_mode_evt
(
hdev
,
skb
);
hci_pscan_rep_mode_evt
(
hdev
,
skb
);
break
;
break
;
...
@@ -1498,6 +1882,18 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -1498,6 +1882,18 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_extended_inquiry_result_evt
(
hdev
,
skb
);
hci_extended_inquiry_result_evt
(
hdev
,
skb
);
break
;
break
;
case
HCI_EV_IO_CAPA_REQUEST
:
hci_io_capa_request_evt
(
hdev
,
skb
);
break
;
case
HCI_EV_SIMPLE_PAIR_COMPLETE
:
hci_simple_pair_complete_evt
(
hdev
,
skb
);
break
;
case
HCI_EV_REMOTE_HOST_FEATURES
:
hci_remote_host_features_evt
(
hdev
,
skb
);
break
;
default:
default:
BT_DBG
(
"%s event 0x%x"
,
hdev
->
name
,
event
);
BT_DBG
(
"%s event 0x%x"
,
hdev
->
name
,
event
);
break
;
break
;
...
...
net/bluetooth/hci_sock.c
View file @
407d819c
...
@@ -193,19 +193,11 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
...
@@ -193,19 +193,11 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
return
0
;
return
0
;
case
HCISETSECMGR
:
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EACCES
;
if
(
arg
)
set_bit
(
HCI_SECMGR
,
&
hdev
->
flags
);
else
clear_bit
(
HCI_SECMGR
,
&
hdev
->
flags
);
return
0
;
case
HCIGETCONNINFO
:
case
HCIGETCONNINFO
:
return
hci_get_conn_info
(
hdev
,
(
void
__user
*
)
arg
);
return
hci_get_conn_info
(
hdev
,
(
void
__user
*
)
arg
);
case
HCIGETAUTHINFO
:
return
hci_get_auth_info
(
hdev
,
(
void
__user
*
)
arg
);
default:
default:
if
(
hdev
->
ioctl
)
if
(
hdev
->
ioctl
)
...
@@ -217,7 +209,7 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
...
@@ -217,7 +209,7 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
static
int
hci_sock_ioctl
(
struct
socket
*
sock
,
unsigned
int
cmd
,
unsigned
long
arg
)
static
int
hci_sock_ioctl
(
struct
socket
*
sock
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
int
err
;
int
err
;
BT_DBG
(
"cmd %x arg %lx"
,
cmd
,
arg
);
BT_DBG
(
"cmd %x arg %lx"
,
cmd
,
arg
);
...
...
net/bluetooth/hci_sysfs.c
View file @
407d819c
...
@@ -113,11 +113,13 @@ static ssize_t show_inquiry_cache(struct device *dev, struct device_attribute *a
...
@@ -113,11 +113,13 @@ static ssize_t show_inquiry_cache(struct device *dev, struct device_attribute *a
struct
inquiry_data
*
data
=
&
e
->
data
;
struct
inquiry_data
*
data
=
&
e
->
data
;
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
baswap
(
&
bdaddr
,
&
data
->
bdaddr
);
baswap
(
&
bdaddr
,
&
data
->
bdaddr
);
n
+=
sprintf
(
buf
+
n
,
"%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %u
\n
"
,
n
+=
sprintf
(
buf
+
n
,
"%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %
d %
u
\n
"
,
batostr
(
&
bdaddr
),
batostr
(
&
bdaddr
),
data
->
pscan_rep_mode
,
data
->
pscan_period_mode
,
data
->
pscan_mode
,
data
->
pscan_rep_mode
,
data
->
pscan_period_mode
,
data
->
dev_class
[
2
],
data
->
dev_class
[
1
],
data
->
dev_class
[
0
],
data
->
pscan_mode
,
data
->
dev_class
[
2
],
__le16_to_cpu
(
data
->
clock_offset
),
data
->
rssi
,
e
->
timestamp
);
data
->
dev_class
[
1
],
data
->
dev_class
[
0
],
__le16_to_cpu
(
data
->
clock_offset
),
data
->
rssi
,
data
->
ssp_mode
,
e
->
timestamp
);
}
}
hci_dev_unlock_bh
(
hdev
);
hci_dev_unlock_bh
(
hdev
);
...
@@ -249,15 +251,28 @@ static ssize_t show_conn_address(struct device *dev, struct device_attribute *at
...
@@ -249,15 +251,28 @@ static ssize_t show_conn_address(struct device *dev, struct device_attribute *at
return
sprintf
(
buf
,
"%s
\n
"
,
batostr
(
&
bdaddr
));
return
sprintf
(
buf
,
"%s
\n
"
,
batostr
(
&
bdaddr
));
}
}
static
ssize_t
show_conn_features
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
hci_conn
*
conn
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"0x%02x%02x%02x%02x%02x%02x%02x%02x
\n
"
,
conn
->
features
[
0
],
conn
->
features
[
1
],
conn
->
features
[
2
],
conn
->
features
[
3
],
conn
->
features
[
4
],
conn
->
features
[
5
],
conn
->
features
[
6
],
conn
->
features
[
7
]);
}
#define CONN_ATTR(_name,_mode,_show,_store) \
#define CONN_ATTR(_name,_mode,_show,_store) \
struct device_attribute conn_attr_##_name = __ATTR(_name,_mode,_show,_store)
struct device_attribute conn_attr_##_name = __ATTR(_name,_mode,_show,_store)
static
CONN_ATTR
(
type
,
S_IRUGO
,
show_conn_type
,
NULL
);
static
CONN_ATTR
(
type
,
S_IRUGO
,
show_conn_type
,
NULL
);
static
CONN_ATTR
(
address
,
S_IRUGO
,
show_conn_address
,
NULL
);
static
CONN_ATTR
(
address
,
S_IRUGO
,
show_conn_address
,
NULL
);
static
CONN_ATTR
(
features
,
S_IRUGO
,
show_conn_features
,
NULL
);
static
struct
device_attribute
*
conn_attrs
[]
=
{
static
struct
device_attribute
*
conn_attrs
[]
=
{
&
conn_attr_type
,
&
conn_attr_type
,
&
conn_attr_address
,
&
conn_attr_address
,
&
conn_attr_features
,
NULL
NULL
};
};
...
@@ -296,7 +311,6 @@ static void add_conn(struct work_struct *work)
...
@@ -296,7 +311,6 @@ static void add_conn(struct work_struct *work)
void
hci_conn_add_sysfs
(
struct
hci_conn
*
conn
)
void
hci_conn_add_sysfs
(
struct
hci_conn
*
conn
)
{
{
struct
hci_dev
*
hdev
=
conn
->
hdev
;
struct
hci_dev
*
hdev
=
conn
->
hdev
;
bdaddr_t
*
ba
=
&
conn
->
dst
;
BT_DBG
(
"conn %p"
,
conn
);
BT_DBG
(
"conn %p"
,
conn
);
...
@@ -305,11 +319,8 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
...
@@ -305,11 +319,8 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
conn
->
dev
.
release
=
bt_release
;
conn
->
dev
.
release
=
bt_release
;
snprintf
(
conn
->
dev
.
bus_id
,
BUS_ID_SIZE
,
snprintf
(
conn
->
dev
.
bus_id
,
BUS_ID_SIZE
,
"%s:%d"
,
"%s%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X"
,
hdev
->
name
,
conn
->
handle
);
conn
->
type
==
ACL_LINK
?
"acl"
:
"sco"
,
ba
->
b
[
5
],
ba
->
b
[
4
],
ba
->
b
[
3
],
ba
->
b
[
2
],
ba
->
b
[
1
],
ba
->
b
[
0
]);
dev_set_drvdata
(
&
conn
->
dev
,
conn
);
dev_set_drvdata
(
&
conn
->
dev
,
conn
);
...
...
net/bluetooth/hidp/core.c
View file @
407d819c
...
@@ -581,6 +581,12 @@ static int hidp_session(void *arg)
...
@@ -581,6 +581,12 @@ static int hidp_session(void *arg)
hid_free_device
(
session
->
hid
);
hid_free_device
(
session
->
hid
);
}
}
/* Wakeup user-space polling for socket errors */
session
->
intr_sock
->
sk
->
sk_err
=
EUNATCH
;
session
->
ctrl_sock
->
sk
->
sk_err
=
EUNATCH
;
hidp_schedule
(
session
);
fput
(
session
->
intr_sock
->
file
);
fput
(
session
->
intr_sock
->
file
);
wait_event_timeout
(
*
(
ctrl_sk
->
sk_sleep
),
wait_event_timeout
(
*
(
ctrl_sk
->
sk_sleep
),
...
@@ -879,6 +885,10 @@ int hidp_del_connection(struct hidp_conndel_req *req)
...
@@ -879,6 +885,10 @@ int hidp_del_connection(struct hidp_conndel_req *req)
skb_queue_purge
(
&
session
->
ctrl_transmit
);
skb_queue_purge
(
&
session
->
ctrl_transmit
);
skb_queue_purge
(
&
session
->
intr_transmit
);
skb_queue_purge
(
&
session
->
intr_transmit
);
/* Wakeup user-space polling for socket errors */
session
->
intr_sock
->
sk
->
sk_err
=
EUNATCH
;
session
->
ctrl_sock
->
sk
->
sk_err
=
EUNATCH
;
/* Kill session thread */
/* Kill session thread */
atomic_inc
(
&
session
->
terminate
);
atomic_inc
(
&
session
->
terminate
);
hidp_schedule
(
session
);
hidp_schedule
(
session
);
...
...
net/bluetooth/l2cap.c
View file @
407d819c
...
@@ -55,7 +55,7 @@
...
@@ -55,7 +55,7 @@
#define BT_DBG(D...)
#define BT_DBG(D...)
#endif
#endif
#define VERSION "2.
9
"
#define VERSION "2.
10
"
static
u32
l2cap_feat_mask
=
0x0000
;
static
u32
l2cap_feat_mask
=
0x0000
;
...
@@ -76,11 +76,21 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
...
@@ -76,11 +76,21 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
static
void
l2cap_sock_timeout
(
unsigned
long
arg
)
static
void
l2cap_sock_timeout
(
unsigned
long
arg
)
{
{
struct
sock
*
sk
=
(
struct
sock
*
)
arg
;
struct
sock
*
sk
=
(
struct
sock
*
)
arg
;
int
reason
;
BT_DBG
(
"sock %p state %d"
,
sk
,
sk
->
sk_state
);
BT_DBG
(
"sock %p state %d"
,
sk
,
sk
->
sk_state
);
bh_lock_sock
(
sk
);
bh_lock_sock
(
sk
);
__l2cap_sock_close
(
sk
,
ETIMEDOUT
);
if
(
sk
->
sk_state
==
BT_CONNECT
&&
(
l2cap_pi
(
sk
)
->
link_mode
&
(
L2CAP_LM_AUTH
|
L2CAP_LM_ENCRYPT
|
L2CAP_LM_SECURE
)))
reason
=
ECONNREFUSED
;
else
reason
=
ETIMEDOUT
;
__l2cap_sock_close
(
sk
,
reason
);
bh_unlock_sock
(
sk
);
bh_unlock_sock
(
sk
);
l2cap_sock_kill
(
sk
);
l2cap_sock_kill
(
sk
);
...
@@ -240,7 +250,7 @@ static void l2cap_chan_del(struct sock *sk, int err)
...
@@ -240,7 +250,7 @@ static void l2cap_chan_del(struct sock *sk, int err)
hci_conn_put
(
conn
->
hcon
);
hci_conn_put
(
conn
->
hcon
);
}
}
sk
->
sk_state
=
BT_CLOSED
;
sk
->
sk_state
=
BT_CLOSED
;
sock_set_flag
(
sk
,
SOCK_ZAPPED
);
sock_set_flag
(
sk
,
SOCK_ZAPPED
);
if
(
err
)
if
(
err
)
...
@@ -253,6 +263,21 @@ static void l2cap_chan_del(struct sock *sk, int err)
...
@@ -253,6 +263,21 @@ static void l2cap_chan_del(struct sock *sk, int err)
sk
->
sk_state_change
(
sk
);
sk
->
sk_state_change
(
sk
);
}
}
/* Service level security */
static
inline
int
l2cap_check_link_mode
(
struct
sock
*
sk
)
{
struct
l2cap_conn
*
conn
=
l2cap_pi
(
sk
)
->
conn
;
if
((
l2cap_pi
(
sk
)
->
link_mode
&
L2CAP_LM_ENCRYPT
)
||
(
l2cap_pi
(
sk
)
->
link_mode
&
L2CAP_LM_SECURE
))
return
hci_conn_encrypt
(
conn
->
hcon
);
if
(
l2cap_pi
(
sk
)
->
link_mode
&
L2CAP_LM_AUTH
)
return
hci_conn_auth
(
conn
->
hcon
);
return
1
;
}
static
inline
u8
l2cap_get_ident
(
struct
l2cap_conn
*
conn
)
static
inline
u8
l2cap_get_ident
(
struct
l2cap_conn
*
conn
)
{
{
u8
id
;
u8
id
;
...
@@ -287,6 +312,36 @@ static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16
...
@@ -287,6 +312,36 @@ static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16
return
hci_send_acl
(
conn
->
hcon
,
skb
,
0
);
return
hci_send_acl
(
conn
->
hcon
,
skb
,
0
);
}
}
static
void
l2cap_do_start
(
struct
sock
*
sk
)
{
struct
l2cap_conn
*
conn
=
l2cap_pi
(
sk
)
->
conn
;
if
(
conn
->
info_state
&
L2CAP_INFO_FEAT_MASK_REQ_SENT
)
{
if
(
l2cap_check_link_mode
(
sk
))
{
struct
l2cap_conn_req
req
;
req
.
scid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
scid
);
req
.
psm
=
l2cap_pi
(
sk
)
->
psm
;
l2cap_pi
(
sk
)
->
ident
=
l2cap_get_ident
(
conn
);
l2cap_send_cmd
(
conn
,
l2cap_pi
(
sk
)
->
ident
,
L2CAP_CONN_REQ
,
sizeof
(
req
),
&
req
);
}
}
else
{
struct
l2cap_info_req
req
;
req
.
type
=
cpu_to_le16
(
L2CAP_IT_FEAT_MASK
);
conn
->
info_state
|=
L2CAP_INFO_FEAT_MASK_REQ_SENT
;
conn
->
info_ident
=
l2cap_get_ident
(
conn
);
mod_timer
(
&
conn
->
info_timer
,
jiffies
+
msecs_to_jiffies
(
L2CAP_INFO_TIMEOUT
));
l2cap_send_cmd
(
conn
,
conn
->
info_ident
,
L2CAP_INFO_REQ
,
sizeof
(
req
),
&
req
);
}
}
/* ---- L2CAP connections ---- */
/* ---- L2CAP connections ---- */
static
void
l2cap_conn_start
(
struct
l2cap_conn
*
conn
)
static
void
l2cap_conn_start
(
struct
l2cap_conn
*
conn
)
{
{
...
@@ -301,16 +356,37 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
...
@@ -301,16 +356,37 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
bh_lock_sock
(
sk
);
bh_lock_sock
(
sk
);
if
(
sk
->
sk_type
!=
SOCK_SEQPACKET
)
{
if
(
sk
->
sk_type
!=
SOCK_SEQPACKET
)
{
l2cap_sock_clear_timer
(
sk
);
bh_unlock_sock
(
sk
);
sk
->
sk_state
=
BT_CONNECTED
;
continue
;
sk
->
sk_state_change
(
sk
);
}
}
else
if
(
sk
->
sk_state
==
BT_CONNECT
)
{
struct
l2cap_conn_req
req
;
if
(
sk
->
sk_state
==
BT_CONNECT
)
{
l2cap_pi
(
sk
)
->
ident
=
l2cap_get_ident
(
conn
);
if
(
l2cap_check_link_mode
(
sk
))
{
req
.
scid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
scid
);
struct
l2cap_conn_req
req
;
req
.
psm
=
l2cap_pi
(
sk
)
->
psm
;
req
.
scid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
scid
);
l2cap_send_cmd
(
conn
,
l2cap_pi
(
sk
)
->
ident
,
req
.
psm
=
l2cap_pi
(
sk
)
->
psm
;
l2cap_pi
(
sk
)
->
ident
=
l2cap_get_ident
(
conn
);
l2cap_send_cmd
(
conn
,
l2cap_pi
(
sk
)
->
ident
,
L2CAP_CONN_REQ
,
sizeof
(
req
),
&
req
);
L2CAP_CONN_REQ
,
sizeof
(
req
),
&
req
);
}
}
else
if
(
sk
->
sk_state
==
BT_CONNECT2
)
{
struct
l2cap_conn_rsp
rsp
;
rsp
.
scid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
dcid
);
rsp
.
dcid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
scid
);
if
(
l2cap_check_link_mode
(
sk
))
{
sk
->
sk_state
=
BT_CONFIG
;
rsp
.
result
=
cpu_to_le16
(
L2CAP_CR_SUCCESS
);
rsp
.
status
=
cpu_to_le16
(
L2CAP_CS_NO_INFO
);
}
else
{
rsp
.
result
=
cpu_to_le16
(
L2CAP_CR_PEND
);
rsp
.
status
=
cpu_to_le16
(
L2CAP_CS_AUTHEN_PEND
);
}
l2cap_send_cmd
(
conn
,
l2cap_pi
(
sk
)
->
ident
,
L2CAP_CONN_RSP
,
sizeof
(
rsp
),
&
rsp
);
}
}
bh_unlock_sock
(
sk
);
bh_unlock_sock
(
sk
);
...
@@ -321,22 +397,27 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
...
@@ -321,22 +397,27 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
static
void
l2cap_conn_ready
(
struct
l2cap_conn
*
conn
)
static
void
l2cap_conn_ready
(
struct
l2cap_conn
*
conn
)
{
{
BT_DBG
(
"conn %p"
,
conn
);
struct
l2cap_chan_list
*
l
=
&
conn
->
chan_list
;
struct
sock
*
sk
;
if
(
conn
->
chan_list
.
head
||
!
hlist_empty
(
&
l2cap_sk_list
.
head
))
{
BT_DBG
(
"conn %p"
,
conn
);
struct
l2cap_info_req
req
;
req
.
type
=
cpu_to_le16
(
L2CAP_IT_FEAT_MASK
);
read_lock
(
&
l
->
lock
);
conn
->
info_state
|=
L2CAP_INFO_FEAT_MASK_REQ_SENT
;
for
(
sk
=
l
->
head
;
sk
;
sk
=
l2cap_pi
(
sk
)
->
next_c
)
{
conn
->
info_ident
=
l2cap_get_ident
(
conn
);
bh_lock_sock
(
sk
);
mod_timer
(
&
conn
->
info_timer
,
if
(
sk
->
sk_type
!=
SOCK_SEQPACKET
)
{
jiffies
+
msecs_to_jiffies
(
L2CAP_INFO_TIMEOUT
));
l2cap_sock_clear_timer
(
sk
);
sk
->
sk_state
=
BT_CONNECTED
;
sk
->
sk_state_change
(
sk
);
}
else
if
(
sk
->
sk_state
==
BT_CONNECT
)
l2cap_do_start
(
sk
);
l2cap_send_cmd
(
conn
,
conn
->
info_ident
,
bh_unlock_sock
(
sk
);
L2CAP_INFO_REQ
,
sizeof
(
req
),
&
req
);
}
}
read_unlock
(
&
l
->
lock
);
}
}
/* Notify sockets that we cannot guaranty reliability anymore */
/* Notify sockets that we cannot guaranty reliability anymore */
...
@@ -388,7 +469,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
...
@@ -388,7 +469,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
conn
->
feat_mask
=
0
;
conn
->
feat_mask
=
0
;
setup_timer
(
&
conn
->
info_timer
,
l2cap_info_timeout
,
(
unsigned
long
)
conn
);
setup_timer
(
&
conn
->
info_timer
,
l2cap_info_timeout
,
(
unsigned
long
)
conn
);
spin_lock_init
(
&
conn
->
lock
);
spin_lock_init
(
&
conn
->
lock
);
rwlock_init
(
&
conn
->
chan_list
.
lock
);
rwlock_init
(
&
conn
->
chan_list
.
lock
);
...
@@ -500,7 +582,7 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
...
@@ -500,7 +582,7 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
while
((
sk
=
bt_accept_dequeue
(
parent
,
NULL
)))
while
((
sk
=
bt_accept_dequeue
(
parent
,
NULL
)))
l2cap_sock_close
(
sk
);
l2cap_sock_close
(
sk
);
parent
->
sk_state
=
BT_CLOSED
;
parent
->
sk_state
=
BT_CLOSED
;
sock_set_flag
(
parent
,
SOCK_ZAPPED
);
sock_set_flag
(
parent
,
SOCK_ZAPPED
);
}
}
...
@@ -543,9 +625,8 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
...
@@ -543,9 +625,8 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
req
.
scid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
scid
);
req
.
scid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
scid
);
l2cap_send_cmd
(
conn
,
l2cap_get_ident
(
conn
),
l2cap_send_cmd
(
conn
,
l2cap_get_ident
(
conn
),
L2CAP_DISCONN_REQ
,
sizeof
(
req
),
&
req
);
L2CAP_DISCONN_REQ
,
sizeof
(
req
),
&
req
);
}
else
{
}
else
l2cap_chan_del
(
sk
,
reason
);
l2cap_chan_del
(
sk
,
reason
);
}
break
;
break
;
case
BT_CONNECT
:
case
BT_CONNECT
:
...
@@ -614,9 +695,9 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
...
@@ -614,9 +695,9 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
sock_reset_flag
(
sk
,
SOCK_ZAPPED
);
sock_reset_flag
(
sk
,
SOCK_ZAPPED
);
sk
->
sk_protocol
=
proto
;
sk
->
sk_protocol
=
proto
;
sk
->
sk_state
=
BT_OPEN
;
sk
->
sk_state
=
BT_OPEN
;
setup_timer
(
&
sk
->
sk_timer
,
l2cap_sock_timeout
,
(
unsigned
long
)
sk
);
setup_timer
(
&
sk
->
sk_timer
,
l2cap_sock_timeout
,
(
unsigned
long
)
sk
);
bt_sock_link
(
&
l2cap_sk_list
,
sk
);
bt_sock_link
(
&
l2cap_sk_list
,
sk
);
return
sk
;
return
sk
;
...
@@ -729,22 +810,11 @@ static int l2cap_do_connect(struct sock *sk)
...
@@ -729,22 +810,11 @@ static int l2cap_do_connect(struct sock *sk)
l2cap_sock_set_timer
(
sk
,
sk
->
sk_sndtimeo
);
l2cap_sock_set_timer
(
sk
,
sk
->
sk_sndtimeo
);
if
(
hcon
->
state
==
BT_CONNECTED
)
{
if
(
hcon
->
state
==
BT_CONNECTED
)
{
if
(
!
(
conn
->
info_state
&
L2CAP_INFO_FEAT_MASK_REQ_SENT
))
{
if
(
sk
->
sk_type
!=
SOCK_SEQPACKET
)
{
l2cap_conn_ready
(
conn
);
goto
done
;
}
if
(
sk
->
sk_type
==
SOCK_SEQPACKET
)
{
struct
l2cap_conn_req
req
;
l2cap_pi
(
sk
)
->
ident
=
l2cap_get_ident
(
conn
);
req
.
scid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
scid
);
req
.
psm
=
l2cap_pi
(
sk
)
->
psm
;
l2cap_send_cmd
(
conn
,
l2cap_pi
(
sk
)
->
ident
,
L2CAP_CONN_REQ
,
sizeof
(
req
),
&
req
);
}
else
{
l2cap_sock_clear_timer
(
sk
);
l2cap_sock_clear_timer
(
sk
);
sk
->
sk_state
=
BT_CONNECTED
;
sk
->
sk_state
=
BT_CONNECTED
;
}
}
else
l2cap_do_start
(
sk
);
}
}
done:
done:
...
@@ -1145,7 +1215,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
...
@@ -1145,7 +1215,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
__l2cap_sock_close
(
sk
,
0
);
__l2cap_sock_close
(
sk
,
0
);
if
(
sock_flag
(
sk
,
SOCK_LINGER
)
&&
sk
->
sk_lingertime
)
if
(
sock_flag
(
sk
,
SOCK_LINGER
)
&&
sk
->
sk_lingertime
)
err
=
bt_sock_wait_state
(
sk
,
BT_CLOSED
,
sk
->
sk_lingertime
);
err
=
bt_sock_wait_state
(
sk
,
BT_CLOSED
,
sk
->
sk_lingertime
);
}
}
release_sock
(
sk
);
release_sock
(
sk
);
return
err
;
return
err
;
...
@@ -1189,6 +1260,11 @@ static void l2cap_chan_ready(struct sock *sk)
...
@@ -1189,6 +1260,11 @@ static void l2cap_chan_ready(struct sock *sk)
*/
*/
parent
->
sk_data_ready
(
parent
,
0
);
parent
->
sk_data_ready
(
parent
,
0
);
}
}
if
(
l2cap_pi
(
sk
)
->
link_mode
&
L2CAP_LM_SECURE
)
{
struct
l2cap_conn
*
conn
=
l2cap_pi
(
sk
)
->
conn
;
hci_conn_change_link_key
(
conn
->
hcon
);
}
}
}
/* Copy frame to all raw sockets on that connection */
/* Copy frame to all raw sockets on that connection */
...
@@ -1477,7 +1553,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
...
@@ -1477,7 +1553,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
struct
l2cap_conn_req
*
req
=
(
struct
l2cap_conn_req
*
)
data
;
struct
l2cap_conn_req
*
req
=
(
struct
l2cap_conn_req
*
)
data
;
struct
l2cap_conn_rsp
rsp
;
struct
l2cap_conn_rsp
rsp
;
struct
sock
*
sk
,
*
parent
;
struct
sock
*
sk
,
*
parent
;
int
result
=
0
,
status
=
0
;
int
result
,
status
=
0
;
u16
dcid
=
0
,
scid
=
__le16_to_cpu
(
req
->
scid
);
u16
dcid
=
0
,
scid
=
__le16_to_cpu
(
req
->
scid
);
__le16
psm
=
req
->
psm
;
__le16
psm
=
req
->
psm
;
...
@@ -1526,25 +1602,24 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
...
@@ -1526,25 +1602,24 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
l2cap_sock_set_timer
(
sk
,
sk
->
sk_sndtimeo
);
l2cap_sock_set_timer
(
sk
,
sk
->
sk_sndtimeo
);
/* Service level security */
result
=
L2CAP_CR_PEND
;
status
=
L2CAP_CS_AUTHEN_PEND
;
sk
->
sk_state
=
BT_CONNECT2
;
l2cap_pi
(
sk
)
->
ident
=
cmd
->
ident
;
l2cap_pi
(
sk
)
->
ident
=
cmd
->
ident
;
if
((
l2cap_pi
(
sk
)
->
link_mode
&
L2CAP_LM_ENCRYPT
)
||
if
(
conn
->
info_state
&
L2CAP_INFO_FEAT_MASK_REQ_SENT
)
{
(
l2cap_pi
(
sk
)
->
link_mode
&
L2CAP_LM_SECURE
))
{
if
(
l2cap_check_link_mode
(
sk
))
{
if
(
!
hci_conn_encrypt
(
conn
->
hcon
))
sk
->
sk_state
=
BT_CONFIG
;
goto
done
;
result
=
L2CAP_CR_SUCCESS
;
}
else
if
(
l2cap_pi
(
sk
)
->
link_mode
&
L2CAP_LM_AUTH
)
{
status
=
L2CAP_CS_NO_INFO
;
if
(
!
hci_conn_auth
(
conn
->
hcon
))
}
else
{
goto
done
;
sk
->
sk_state
=
BT_CONNECT2
;
result
=
L2CAP_CR_PEND
;
status
=
L2CAP_CS_AUTHEN_PEND
;
}
}
else
{
sk
->
sk_state
=
BT_CONNECT2
;
result
=
L2CAP_CR_PEND
;
status
=
L2CAP_CS_NO_INFO
;
}
}
sk
->
sk_state
=
BT_CONFIG
;
result
=
status
=
0
;
done:
write_unlock_bh
(
&
list
->
lock
);
write_unlock_bh
(
&
list
->
lock
);
response:
response:
...
@@ -1556,6 +1631,21 @@ sendresp:
...
@@ -1556,6 +1631,21 @@ sendresp:
rsp
.
result
=
cpu_to_le16
(
result
);
rsp
.
result
=
cpu_to_le16
(
result
);
rsp
.
status
=
cpu_to_le16
(
status
);
rsp
.
status
=
cpu_to_le16
(
status
);
l2cap_send_cmd
(
conn
,
cmd
->
ident
,
L2CAP_CONN_RSP
,
sizeof
(
rsp
),
&
rsp
);
l2cap_send_cmd
(
conn
,
cmd
->
ident
,
L2CAP_CONN_RSP
,
sizeof
(
rsp
),
&
rsp
);
if
(
result
==
L2CAP_CR_PEND
&&
status
==
L2CAP_CS_NO_INFO
)
{
struct
l2cap_info_req
info
;
info
.
type
=
cpu_to_le16
(
L2CAP_IT_FEAT_MASK
);
conn
->
info_state
|=
L2CAP_INFO_FEAT_MASK_REQ_SENT
;
conn
->
info_ident
=
l2cap_get_ident
(
conn
);
mod_timer
(
&
conn
->
info_timer
,
jiffies
+
msecs_to_jiffies
(
L2CAP_INFO_TIMEOUT
));
l2cap_send_cmd
(
conn
,
conn
->
info_ident
,
L2CAP_INFO_REQ
,
sizeof
(
info
),
&
info
);
}
return
0
;
return
0
;
}
}
...
@@ -1664,9 +1754,9 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
...
@@ -1664,9 +1754,9 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
}
}
if
(
!
(
l2cap_pi
(
sk
)
->
conf_state
&
L2CAP_CONF_REQ_SENT
))
{
if
(
!
(
l2cap_pi
(
sk
)
->
conf_state
&
L2CAP_CONF_REQ_SENT
))
{
u8
req
[
64
];
u8
buf
[
64
];
l2cap_send_cmd
(
conn
,
l2cap_get_ident
(
conn
),
L2CAP_CONF_REQ
,
l2cap_send_cmd
(
conn
,
l2cap_get_ident
(
conn
),
L2CAP_CONF_REQ
,
l2cap_build_conf_req
(
sk
,
req
),
req
);
l2cap_build_conf_req
(
sk
,
buf
),
buf
);
}
}
unlock:
unlock:
...
@@ -1708,7 +1798,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
...
@@ -1708,7 +1798,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
default:
default:
sk
->
sk_state
=
BT_DISCONN
;
sk
->
sk_state
=
BT_DISCONN
;
sk
->
sk_err
=
ECONNRESET
;
sk
->
sk_err
=
ECONNRESET
;
l2cap_sock_set_timer
(
sk
,
HZ
*
5
);
l2cap_sock_set_timer
(
sk
,
HZ
*
5
);
{
{
struct
l2cap_disconn_req
req
;
struct
l2cap_disconn_req
req
;
...
@@ -2080,10 +2170,8 @@ static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason)
...
@@ -2080,10 +2170,8 @@ static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason)
static
int
l2cap_auth_cfm
(
struct
hci_conn
*
hcon
,
u8
status
)
static
int
l2cap_auth_cfm
(
struct
hci_conn
*
hcon
,
u8
status
)
{
{
struct
l2cap_chan_list
*
l
;
struct
l2cap_chan_list
*
l
;
struct
l2cap_conn
*
conn
=
conn
=
hcon
->
l2cap_data
;
struct
l2cap_conn
*
conn
=
hcon
->
l2cap_data
;
struct
l2cap_conn_rsp
rsp
;
struct
sock
*
sk
;
struct
sock
*
sk
;
int
result
;
if
(
!
conn
)
if
(
!
conn
)
return
0
;
return
0
;
...
@@ -2095,45 +2183,65 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
...
@@ -2095,45 +2183,65 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
read_lock
(
&
l
->
lock
);
read_lock
(
&
l
->
lock
);
for
(
sk
=
l
->
head
;
sk
;
sk
=
l2cap_pi
(
sk
)
->
next_c
)
{
for
(
sk
=
l
->
head
;
sk
;
sk
=
l2cap_pi
(
sk
)
->
next_c
)
{
struct
l2cap_pinfo
*
pi
=
l2cap_pi
(
sk
);
bh_lock_sock
(
sk
);
bh_lock_sock
(
sk
);
if
(
sk
->
sk_state
!=
BT_CONNECT2
||
if
(
(
pi
->
link_mode
&
(
L2CAP_LM_ENCRYPT
|
L2CAP_LM_SECURE
))
&&
(
l2cap_pi
(
sk
)
->
link_mode
&
L2CAP_LM_ENCRYPT
)
||
!
(
hcon
->
link_mode
&
HCI_LM_ENCRYPT
)
&&
(
l2cap_pi
(
sk
)
->
link_mode
&
L2CAP_LM_SECURE
)
)
{
!
status
)
{
bh_unlock_sock
(
sk
);
bh_unlock_sock
(
sk
);
continue
;
continue
;
}
}
if
(
!
status
)
{
if
(
sk
->
sk_state
==
BT_CONNECT
)
{
sk
->
sk_state
=
BT_CONFIG
;
if
(
!
status
)
{
result
=
0
;
struct
l2cap_conn_req
req
;
}
else
{
req
.
scid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
scid
);
sk
->
sk_state
=
BT_DISCONN
;
req
.
psm
=
l2cap_pi
(
sk
)
->
psm
;
l2cap_sock_set_timer
(
sk
,
HZ
/
10
);
result
=
L2CAP_CR_SEC_BLOCK
;
}
rsp
.
scid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
dcid
);
l2cap_pi
(
sk
)
->
ident
=
l2cap_get_ident
(
conn
);
rsp
.
dcid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
scid
);
rsp
.
result
=
cpu_to_le16
(
result
);
l2cap_send_cmd
(
conn
,
l2cap_pi
(
sk
)
->
ident
,
rsp
.
status
=
cpu_to_le16
(
0
);
L2CAP_CONN_REQ
,
sizeof
(
req
),
&
req
);
l2cap_send_cmd
(
conn
,
l2cap_pi
(
sk
)
->
ident
,
}
else
{
L2CAP_CONN_RSP
,
sizeof
(
rsp
),
&
rsp
);
l2cap_sock_clear_timer
(
sk
);
l2cap_sock_set_timer
(
sk
,
HZ
/
10
);
}
}
else
if
(
sk
->
sk_state
==
BT_CONNECT2
)
{
struct
l2cap_conn_rsp
rsp
;
__u16
result
;
if
(
!
status
)
{
sk
->
sk_state
=
BT_CONFIG
;
result
=
L2CAP_CR_SUCCESS
;
}
else
{
sk
->
sk_state
=
BT_DISCONN
;
l2cap_sock_set_timer
(
sk
,
HZ
/
10
);
result
=
L2CAP_CR_SEC_BLOCK
;
}
rsp
.
scid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
dcid
);
rsp
.
dcid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
scid
);
rsp
.
result
=
cpu_to_le16
(
result
);
rsp
.
status
=
cpu_to_le16
(
0
);
l2cap_send_cmd
(
conn
,
l2cap_pi
(
sk
)
->
ident
,
L2CAP_CONN_RSP
,
sizeof
(
rsp
),
&
rsp
);
}
bh_unlock_sock
(
sk
);
bh_unlock_sock
(
sk
);
}
}
read_unlock
(
&
l
->
lock
);
read_unlock
(
&
l
->
lock
);
return
0
;
return
0
;
}
}
static
int
l2cap_encrypt_cfm
(
struct
hci_conn
*
hcon
,
u8
status
)
static
int
l2cap_encrypt_cfm
(
struct
hci_conn
*
hcon
,
u8
status
,
u8
encrypt
)
{
{
struct
l2cap_chan_list
*
l
;
struct
l2cap_chan_list
*
l
;
struct
l2cap_conn
*
conn
=
hcon
->
l2cap_data
;
struct
l2cap_conn
*
conn
=
hcon
->
l2cap_data
;
struct
l2cap_conn_rsp
rsp
;
struct
sock
*
sk
;
struct
sock
*
sk
;
int
result
;
if
(
!
conn
)
if
(
!
conn
)
return
0
;
return
0
;
...
@@ -2145,36 +2253,59 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status)
...
@@ -2145,36 +2253,59 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status)
read_lock
(
&
l
->
lock
);
read_lock
(
&
l
->
lock
);
for
(
sk
=
l
->
head
;
sk
;
sk
=
l2cap_pi
(
sk
)
->
next_c
)
{
for
(
sk
=
l
->
head
;
sk
;
sk
=
l2cap_pi
(
sk
)
->
next_c
)
{
struct
l2cap_pinfo
*
pi
=
l2cap_pi
(
sk
);
bh_lock_sock
(
sk
);
bh_lock_sock
(
sk
);
if
(
sk
->
sk_state
!=
BT_CONNECT2
)
{
if
((
pi
->
link_mode
&
(
L2CAP_LM_ENCRYPT
|
L2CAP_LM_SECURE
))
&&
(
sk
->
sk_state
==
BT_CONNECTED
||
sk
->
sk_state
==
BT_CONFIG
)
&&
!
status
&&
encrypt
==
0x00
)
{
__l2cap_sock_close
(
sk
,
ECONNREFUSED
);
bh_unlock_sock
(
sk
);
bh_unlock_sock
(
sk
);
continue
;
continue
;
}
}
if
(
!
status
)
{
if
(
sk
->
sk_state
==
BT_CONNECT
)
{
sk
->
sk_state
=
BT_CONFIG
;
if
(
!
status
)
{
result
=
0
;
struct
l2cap_conn_req
req
;
}
else
{
req
.
scid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
scid
);
sk
->
sk_state
=
BT_DISCONN
;
req
.
psm
=
l2cap_pi
(
sk
)
->
psm
;
l2cap_sock_set_timer
(
sk
,
HZ
/
10
);
result
=
L2CAP_CR_SEC_BLOCK
;
l2cap_pi
(
sk
)
->
ident
=
l2cap_get_ident
(
conn
);
}
rsp
.
scid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
dcid
);
l2cap_send_cmd
(
conn
,
l2cap_pi
(
sk
)
->
ident
,
rsp
.
dcid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
scid
);
L2CAP_CONN_REQ
,
sizeof
(
req
),
&
req
);
rsp
.
result
=
cpu_to_le16
(
result
);
}
else
{
rsp
.
status
=
cpu_to_le16
(
0
);
l2cap_sock_clear_timer
(
sk
);
l2cap_send_cmd
(
conn
,
l2cap_pi
(
sk
)
->
ident
,
l2cap_sock_set_timer
(
sk
,
HZ
/
10
);
L2CAP_CONN_RSP
,
sizeof
(
rsp
),
&
rsp
);
}
}
else
if
(
sk
->
sk_state
==
BT_CONNECT2
)
{
struct
l2cap_conn_rsp
rsp
;
__u16
result
;
if
(
!
status
)
{
sk
->
sk_state
=
BT_CONFIG
;
result
=
L2CAP_CR_SUCCESS
;
}
else
{
sk
->
sk_state
=
BT_DISCONN
;
l2cap_sock_set_timer
(
sk
,
HZ
/
10
);
result
=
L2CAP_CR_SEC_BLOCK
;
}
if
(
l2cap_pi
(
sk
)
->
link_mode
&
L2CAP_LM_SECURE
)
rsp
.
scid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
dcid
);
hci_conn_change_link_key
(
hcon
);
rsp
.
dcid
=
cpu_to_le16
(
l2cap_pi
(
sk
)
->
scid
);
rsp
.
result
=
cpu_to_le16
(
result
);
rsp
.
status
=
cpu_to_le16
(
0
);
l2cap_send_cmd
(
conn
,
l2cap_pi
(
sk
)
->
ident
,
L2CAP_CONN_RSP
,
sizeof
(
rsp
),
&
rsp
);
}
bh_unlock_sock
(
sk
);
bh_unlock_sock
(
sk
);
}
}
read_unlock
(
&
l
->
lock
);
read_unlock
(
&
l
->
lock
);
return
0
;
return
0
;
}
}
...
@@ -2301,9 +2432,9 @@ static const struct proto_ops l2cap_sock_ops = {
...
@@ -2301,9 +2432,9 @@ static const struct proto_ops l2cap_sock_ops = {
.
sendmsg
=
l2cap_sock_sendmsg
,
.
sendmsg
=
l2cap_sock_sendmsg
,
.
recvmsg
=
bt_sock_recvmsg
,
.
recvmsg
=
bt_sock_recvmsg
,
.
poll
=
bt_sock_poll
,
.
poll
=
bt_sock_poll
,
.
ioctl
=
bt_sock_ioctl
,
.
mmap
=
sock_no_mmap
,
.
mmap
=
sock_no_mmap
,
.
socketpair
=
sock_no_socketpair
,
.
socketpair
=
sock_no_socketpair
,
.
ioctl
=
sock_no_ioctl
,
.
shutdown
=
l2cap_sock_shutdown
,
.
shutdown
=
l2cap_sock_shutdown
,
.
setsockopt
=
l2cap_sock_setsockopt
,
.
setsockopt
=
l2cap_sock_setsockopt
,
.
getsockopt
=
l2cap_sock_getsockopt
.
getsockopt
=
l2cap_sock_getsockopt
...
...
net/bluetooth/rfcomm/core.c
View file @
407d819c
...
@@ -51,7 +51,7 @@
...
@@ -51,7 +51,7 @@
#define BT_DBG(D...)
#define BT_DBG(D...)
#endif
#endif
#define VERSION "1.
8
"
#define VERSION "1.
10
"
static
int
disable_cfc
=
0
;
static
int
disable_cfc
=
0
;
static
int
channel_mtu
=
-
1
;
static
int
channel_mtu
=
-
1
;
...
@@ -228,6 +228,21 @@ static int rfcomm_l2sock_create(struct socket **sock)
...
@@ -228,6 +228,21 @@ static int rfcomm_l2sock_create(struct socket **sock)
return
err
;
return
err
;
}
}
static
inline
int
rfcomm_check_link_mode
(
struct
rfcomm_dlc
*
d
)
{
struct
sock
*
sk
=
d
->
session
->
sock
->
sk
;
if
(
d
->
link_mode
&
(
RFCOMM_LM_ENCRYPT
|
RFCOMM_LM_SECURE
))
{
if
(
!
hci_conn_encrypt
(
l2cap_pi
(
sk
)
->
conn
->
hcon
))
return
1
;
}
else
if
(
d
->
link_mode
&
RFCOMM_LM_AUTH
)
{
if
(
!
hci_conn_auth
(
l2cap_pi
(
sk
)
->
conn
->
hcon
))
return
1
;
}
return
0
;
}
/* ---- RFCOMM DLCs ---- */
/* ---- RFCOMM DLCs ---- */
static
void
rfcomm_dlc_timeout
(
unsigned
long
arg
)
static
void
rfcomm_dlc_timeout
(
unsigned
long
arg
)
{
{
...
@@ -369,15 +384,23 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
...
@@ -369,15 +384,23 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
d
->
addr
=
__addr
(
s
->
initiator
,
dlci
);
d
->
addr
=
__addr
(
s
->
initiator
,
dlci
);
d
->
priority
=
7
;
d
->
priority
=
7
;
d
->
state
=
BT_CONFIG
;
d
->
state
=
BT_CONFIG
;
rfcomm_dlc_link
(
s
,
d
);
rfcomm_dlc_link
(
s
,
d
);
d
->
out
=
1
;
d
->
mtu
=
s
->
mtu
;
d
->
mtu
=
s
->
mtu
;
d
->
cfc
=
(
s
->
cfc
==
RFCOMM_CFC_UNKNOWN
)
?
0
:
s
->
cfc
;
d
->
cfc
=
(
s
->
cfc
==
RFCOMM_CFC_UNKNOWN
)
?
0
:
s
->
cfc
;
if
(
s
->
state
==
BT_CONNECTED
)
if
(
s
->
state
==
BT_CONNECTED
)
{
rfcomm_send_pn
(
s
,
1
,
d
);
if
(
rfcomm_check_link_mode
(
d
))
set_bit
(
RFCOMM_AUTH_PENDING
,
&
d
->
flags
);
else
rfcomm_send_pn
(
s
,
1
,
d
);
}
rfcomm_dlc_set_timer
(
d
,
RFCOMM_CONN_TIMEOUT
);
rfcomm_dlc_set_timer
(
d
,
RFCOMM_CONN_TIMEOUT
);
return
0
;
return
0
;
}
}
...
@@ -1144,21 +1167,6 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
...
@@ -1144,21 +1167,6 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
return
0
;
return
0
;
}
}
static
inline
int
rfcomm_check_link_mode
(
struct
rfcomm_dlc
*
d
)
{
struct
sock
*
sk
=
d
->
session
->
sock
->
sk
;
if
(
d
->
link_mode
&
(
RFCOMM_LM_ENCRYPT
|
RFCOMM_LM_SECURE
))
{
if
(
!
hci_conn_encrypt
(
l2cap_pi
(
sk
)
->
conn
->
hcon
))
return
1
;
}
else
if
(
d
->
link_mode
&
RFCOMM_LM_AUTH
)
{
if
(
!
hci_conn_auth
(
l2cap_pi
(
sk
)
->
conn
->
hcon
))
return
1
;
}
return
0
;
}
static
void
rfcomm_dlc_accept
(
struct
rfcomm_dlc
*
d
)
static
void
rfcomm_dlc_accept
(
struct
rfcomm_dlc
*
d
)
{
{
struct
sock
*
sk
=
d
->
session
->
sock
->
sk
;
struct
sock
*
sk
=
d
->
session
->
sock
->
sk
;
...
@@ -1203,10 +1211,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
...
@@ -1203,10 +1211,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
if
(
rfcomm_check_link_mode
(
d
))
{
if
(
rfcomm_check_link_mode
(
d
))
{
set_bit
(
RFCOMM_AUTH_PENDING
,
&
d
->
flags
);
set_bit
(
RFCOMM_AUTH_PENDING
,
&
d
->
flags
);
rfcomm_dlc_set_timer
(
d
,
RFCOMM_AUTH_TIMEOUT
);
rfcomm_dlc_set_timer
(
d
,
RFCOMM_AUTH_TIMEOUT
);
return
0
;
}
else
}
rfcomm_dlc_accept
(
d
);
rfcomm_dlc_accept
(
d
);
}
}
return
0
;
return
0
;
}
}
...
@@ -1221,10 +1227,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
...
@@ -1221,10 +1227,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
if
(
rfcomm_check_link_mode
(
d
))
{
if
(
rfcomm_check_link_mode
(
d
))
{
set_bit
(
RFCOMM_AUTH_PENDING
,
&
d
->
flags
);
set_bit
(
RFCOMM_AUTH_PENDING
,
&
d
->
flags
);
rfcomm_dlc_set_timer
(
d
,
RFCOMM_AUTH_TIMEOUT
);
rfcomm_dlc_set_timer
(
d
,
RFCOMM_AUTH_TIMEOUT
);
return
0
;
}
else
}
rfcomm_dlc_accept
(
d
);
rfcomm_dlc_accept
(
d
);
}
else
{
}
else
{
rfcomm_send_dm
(
s
,
dlci
);
rfcomm_send_dm
(
s
,
dlci
);
}
}
...
@@ -1457,8 +1461,12 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb
...
@@ -1457,8 +1461,12 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb
clear_bit
(
RFCOMM_TX_THROTTLED
,
&
d
->
flags
);
clear_bit
(
RFCOMM_TX_THROTTLED
,
&
d
->
flags
);
rfcomm_dlc_lock
(
d
);
rfcomm_dlc_lock
(
d
);
d
->
remote_v24_sig
=
msc
->
v24_sig
;
if
(
d
->
modem_status
)
if
(
d
->
modem_status
)
d
->
modem_status
(
d
,
msc
->
v24_sig
);
d
->
modem_status
(
d
,
msc
->
v24_sig
);
rfcomm_dlc_unlock
(
d
);
rfcomm_dlc_unlock
(
d
);
rfcomm_send_msc
(
s
,
0
,
dlci
,
msc
->
v24_sig
);
rfcomm_send_msc
(
s
,
0
,
dlci
,
msc
->
v24_sig
);
...
@@ -1634,7 +1642,11 @@ static void rfcomm_process_connect(struct rfcomm_session *s)
...
@@ -1634,7 +1642,11 @@ static void rfcomm_process_connect(struct rfcomm_session *s)
d
=
list_entry
(
p
,
struct
rfcomm_dlc
,
list
);
d
=
list_entry
(
p
,
struct
rfcomm_dlc
,
list
);
if
(
d
->
state
==
BT_CONFIG
)
{
if
(
d
->
state
==
BT_CONFIG
)
{
d
->
mtu
=
s
->
mtu
;
d
->
mtu
=
s
->
mtu
;
rfcomm_send_pn
(
s
,
1
,
d
);
if
(
rfcomm_check_link_mode
(
d
))
{
set_bit
(
RFCOMM_AUTH_PENDING
,
&
d
->
flags
);
rfcomm_dlc_set_timer
(
d
,
RFCOMM_AUTH_TIMEOUT
);
}
else
rfcomm_send_pn
(
s
,
1
,
d
);
}
}
}
}
}
}
...
@@ -1707,7 +1719,11 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
...
@@ -1707,7 +1719,11 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
if
(
test_and_clear_bit
(
RFCOMM_AUTH_ACCEPT
,
&
d
->
flags
))
{
if
(
test_and_clear_bit
(
RFCOMM_AUTH_ACCEPT
,
&
d
->
flags
))
{
rfcomm_dlc_clear_timer
(
d
);
rfcomm_dlc_clear_timer
(
d
);
rfcomm_dlc_accept
(
d
);
if
(
d
->
out
)
{
rfcomm_send_pn
(
s
,
1
,
d
);
rfcomm_dlc_set_timer
(
d
,
RFCOMM_CONN_TIMEOUT
);
}
else
rfcomm_dlc_accept
(
d
);
if
(
d
->
link_mode
&
RFCOMM_LM_SECURE
)
{
if
(
d
->
link_mode
&
RFCOMM_LM_SECURE
)
{
struct
sock
*
sk
=
s
->
sock
->
sk
;
struct
sock
*
sk
=
s
->
sock
->
sk
;
hci_conn_change_link_key
(
l2cap_pi
(
sk
)
->
conn
->
hcon
);
hci_conn_change_link_key
(
l2cap_pi
(
sk
)
->
conn
->
hcon
);
...
@@ -1715,7 +1731,10 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
...
@@ -1715,7 +1731,10 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
continue
;
continue
;
}
else
if
(
test_and_clear_bit
(
RFCOMM_AUTH_REJECT
,
&
d
->
flags
))
{
}
else
if
(
test_and_clear_bit
(
RFCOMM_AUTH_REJECT
,
&
d
->
flags
))
{
rfcomm_dlc_clear_timer
(
d
);
rfcomm_dlc_clear_timer
(
d
);
rfcomm_send_dm
(
s
,
d
->
dlci
);
if
(
!
d
->
out
)
rfcomm_send_dm
(
s
,
d
->
dlci
);
else
d
->
state
=
BT_CLOSED
;
__rfcomm_dlc_close
(
d
,
ECONNREFUSED
);
__rfcomm_dlc_close
(
d
,
ECONNREFUSED
);
continue
;
continue
;
}
}
...
@@ -1724,7 +1743,7 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
...
@@ -1724,7 +1743,7 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
continue
;
continue
;
if
((
d
->
state
==
BT_CONNECTED
||
d
->
state
==
BT_DISCONN
)
&&
if
((
d
->
state
==
BT_CONNECTED
||
d
->
state
==
BT_DISCONN
)
&&
d
->
mscex
==
RFCOMM_MSCEX_OK
)
d
->
mscex
==
RFCOMM_MSCEX_OK
)
rfcomm_process_tx
(
d
);
rfcomm_process_tx
(
d
);
}
}
}
}
...
@@ -1952,7 +1971,8 @@ static void rfcomm_auth_cfm(struct hci_conn *conn, u8 status)
...
@@ -1952,7 +1971,8 @@ static void rfcomm_auth_cfm(struct hci_conn *conn, u8 status)
list_for_each_safe
(
p
,
n
,
&
s
->
dlcs
)
{
list_for_each_safe
(
p
,
n
,
&
s
->
dlcs
)
{
d
=
list_entry
(
p
,
struct
rfcomm_dlc
,
list
);
d
=
list_entry
(
p
,
struct
rfcomm_dlc
,
list
);
if
(
d
->
link_mode
&
(
RFCOMM_LM_ENCRYPT
|
RFCOMM_LM_SECURE
))
if
((
d
->
link_mode
&
(
RFCOMM_LM_ENCRYPT
|
RFCOMM_LM_SECURE
))
&&
!
(
conn
->
link_mode
&
HCI_LM_ENCRYPT
)
&&
!
status
)
continue
;
continue
;
if
(
!
test_and_clear_bit
(
RFCOMM_AUTH_PENDING
,
&
d
->
flags
))
if
(
!
test_and_clear_bit
(
RFCOMM_AUTH_PENDING
,
&
d
->
flags
))
...
@@ -1986,6 +2006,14 @@ static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
...
@@ -1986,6 +2006,14 @@ static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
list_for_each_safe
(
p
,
n
,
&
s
->
dlcs
)
{
list_for_each_safe
(
p
,
n
,
&
s
->
dlcs
)
{
d
=
list_entry
(
p
,
struct
rfcomm_dlc
,
list
);
d
=
list_entry
(
p
,
struct
rfcomm_dlc
,
list
);
if
((
d
->
link_mode
&
(
RFCOMM_LM_ENCRYPT
|
RFCOMM_LM_SECURE
))
&&
(
d
->
state
==
BT_CONNECTED
||
d
->
state
==
BT_CONFIG
)
&&
!
status
&&
encrypt
==
0x00
)
{
__rfcomm_dlc_close
(
d
,
ECONNREFUSED
);
continue
;
}
if
(
!
test_and_clear_bit
(
RFCOMM_AUTH_PENDING
,
&
d
->
flags
))
if
(
!
test_and_clear_bit
(
RFCOMM_AUTH_PENDING
,
&
d
->
flags
))
continue
;
continue
;
...
...
net/bluetooth/rfcomm/sock.c
View file @
407d819c
...
@@ -307,13 +307,13 @@ static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int
...
@@ -307,13 +307,13 @@ static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int
sk
->
sk_destruct
=
rfcomm_sock_destruct
;
sk
->
sk_destruct
=
rfcomm_sock_destruct
;
sk
->
sk_sndtimeo
=
RFCOMM_CONN_TIMEOUT
;
sk
->
sk_sndtimeo
=
RFCOMM_CONN_TIMEOUT
;
sk
->
sk_sndbuf
=
RFCOMM_MAX_CREDITS
*
RFCOMM_DEFAULT_MTU
*
10
;
sk
->
sk_sndbuf
=
RFCOMM_MAX_CREDITS
*
RFCOMM_DEFAULT_MTU
*
10
;
sk
->
sk_rcvbuf
=
RFCOMM_MAX_CREDITS
*
RFCOMM_DEFAULT_MTU
*
10
;
sk
->
sk_rcvbuf
=
RFCOMM_MAX_CREDITS
*
RFCOMM_DEFAULT_MTU
*
10
;
sock_reset_flag
(
sk
,
SOCK_ZAPPED
);
sock_reset_flag
(
sk
,
SOCK_ZAPPED
);
sk
->
sk_protocol
=
proto
;
sk
->
sk_protocol
=
proto
;
sk
->
sk_state
=
BT_OPEN
;
sk
->
sk_state
=
BT_OPEN
;
bt_sock_link
(
&
rfcomm_sk_list
,
sk
);
bt_sock_link
(
&
rfcomm_sk_list
,
sk
);
...
@@ -411,6 +411,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
...
@@ -411,6 +411,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
bacpy
(
&
bt_sk
(
sk
)
->
dst
,
&
sa
->
rc_bdaddr
);
bacpy
(
&
bt_sk
(
sk
)
->
dst
,
&
sa
->
rc_bdaddr
);
rfcomm_pi
(
sk
)
->
channel
=
sa
->
rc_channel
;
rfcomm_pi
(
sk
)
->
channel
=
sa
->
rc_channel
;
d
->
link_mode
=
rfcomm_pi
(
sk
)
->
link_mode
;
err
=
rfcomm_dlc_open
(
d
,
&
bt_sk
(
sk
)
->
src
,
&
sa
->
rc_bdaddr
,
sa
->
rc_channel
);
err
=
rfcomm_dlc_open
(
d
,
&
bt_sk
(
sk
)
->
src
,
&
sa
->
rc_bdaddr
,
sa
->
rc_channel
);
if
(
!
err
)
if
(
!
err
)
err
=
bt_sock_wait_state
(
sk
,
BT_CONNECTED
,
err
=
bt_sock_wait_state
(
sk
,
BT_CONNECTED
,
...
@@ -686,6 +688,8 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
...
@@ -686,6 +688,8 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
copied
+=
chunk
;
copied
+=
chunk
;
size
-=
chunk
;
size
-=
chunk
;
sock_recv_timestamp
(
msg
,
sk
,
skb
);
if
(
!
(
flags
&
MSG_PEEK
))
{
if
(
!
(
flags
&
MSG_PEEK
))
{
atomic_sub
(
chunk
,
&
sk
->
sk_rmem_alloc
);
atomic_sub
(
chunk
,
&
sk
->
sk_rmem_alloc
);
...
@@ -791,15 +795,20 @@ static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned lon
...
@@ -791,15 +795,20 @@ static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned lon
struct
sock
*
sk
=
sock
->
sk
;
struct
sock
*
sk
=
sock
->
sk
;
int
err
;
int
err
;
lock_sock
(
sk
);
BT_DBG
(
"sk %p cmd %x arg %lx"
,
sk
,
cmd
,
arg
);
err
=
bt_sock_ioctl
(
sock
,
cmd
,
arg
);
if
(
err
==
-
ENOIOCTLCMD
)
{
#ifdef CONFIG_BT_RFCOMM_TTY
#ifdef CONFIG_BT_RFCOMM_TTY
err
=
rfcomm_dev_ioctl
(
sk
,
cmd
,
(
void
__user
*
)
arg
);
lock_sock
(
sk
);
err
=
rfcomm_dev_ioctl
(
sk
,
cmd
,
(
void
__user
*
)
arg
);
release_sock
(
sk
);
#else
#else
err
=
-
EOPNOTSUPP
;
err
=
-
EOPNOTSUPP
;
#endif
#endif
}
release_sock
(
sk
);
return
err
;
return
err
;
}
}
...
...
net/bluetooth/rfcomm/tty.c
View file @
407d819c
...
@@ -75,6 +75,8 @@ struct rfcomm_dev {
...
@@ -75,6 +75,8 @@ struct rfcomm_dev {
struct
device
*
tty_dev
;
struct
device
*
tty_dev
;
atomic_t
wmem_alloc
;
atomic_t
wmem_alloc
;
struct
sk_buff_head
pending
;
};
};
static
LIST_HEAD
(
rfcomm_dev_list
);
static
LIST_HEAD
(
rfcomm_dev_list
);
...
@@ -262,13 +264,34 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
...
@@ -262,13 +264,34 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
init_waitqueue_head
(
&
dev
->
wait
);
init_waitqueue_head
(
&
dev
->
wait
);
tasklet_init
(
&
dev
->
wakeup_task
,
rfcomm_tty_wakeup
,
(
unsigned
long
)
dev
);
tasklet_init
(
&
dev
->
wakeup_task
,
rfcomm_tty_wakeup
,
(
unsigned
long
)
dev
);
skb_queue_head_init
(
&
dev
->
pending
);
rfcomm_dlc_lock
(
dlc
);
rfcomm_dlc_lock
(
dlc
);
if
(
req
->
flags
&
(
1
<<
RFCOMM_REUSE_DLC
))
{
struct
sock
*
sk
=
dlc
->
owner
;
struct
sk_buff
*
skb
;
BUG_ON
(
!
sk
);
rfcomm_dlc_throttle
(
dlc
);
while
((
skb
=
skb_dequeue
(
&
sk
->
sk_receive_queue
)))
{
skb_orphan
(
skb
);
skb_queue_tail
(
&
dev
->
pending
,
skb
);
atomic_sub
(
skb
->
len
,
&
sk
->
sk_rmem_alloc
);
}
}
dlc
->
data_ready
=
rfcomm_dev_data_ready
;
dlc
->
data_ready
=
rfcomm_dev_data_ready
;
dlc
->
state_change
=
rfcomm_dev_state_change
;
dlc
->
state_change
=
rfcomm_dev_state_change
;
dlc
->
modem_status
=
rfcomm_dev_modem_status
;
dlc
->
modem_status
=
rfcomm_dev_modem_status
;
dlc
->
owner
=
dev
;
dlc
->
owner
=
dev
;
dev
->
dlc
=
dlc
;
dev
->
dlc
=
dlc
;
rfcomm_dev_modem_status
(
dlc
,
dlc
->
remote_v24_sig
);
rfcomm_dlc_unlock
(
dlc
);
rfcomm_dlc_unlock
(
dlc
);
/* It's safe to call __module_get() here because socket already
/* It's safe to call __module_get() here because socket already
...
@@ -537,11 +560,16 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
...
@@ -537,11 +560,16 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
struct
rfcomm_dev
*
dev
=
dlc
->
owner
;
struct
rfcomm_dev
*
dev
=
dlc
->
owner
;
struct
tty_struct
*
tty
;
struct
tty_struct
*
tty
;
if
(
!
dev
||
!
(
tty
=
dev
->
tty
)
)
{
if
(
!
dev
)
{
kfree_skb
(
skb
);
kfree_skb
(
skb
);
return
;
return
;
}
}
if
(
!
(
tty
=
dev
->
tty
)
||
!
skb_queue_empty
(
&
dev
->
pending
))
{
skb_queue_tail
(
&
dev
->
pending
,
skb
);
return
;
}
BT_DBG
(
"dlc %p tty %p len %d"
,
dlc
,
tty
,
skb
->
len
);
BT_DBG
(
"dlc %p tty %p len %d"
,
dlc
,
tty
,
skb
->
len
);
tty_insert_flip_string
(
tty
,
skb
->
data
,
skb
->
len
);
tty_insert_flip_string
(
tty
,
skb
->
data
,
skb
->
len
);
...
@@ -625,6 +653,30 @@ static void rfcomm_tty_wakeup(unsigned long arg)
...
@@ -625,6 +653,30 @@ static void rfcomm_tty_wakeup(unsigned long arg)
#endif
#endif
}
}
static
void
rfcomm_tty_copy_pending
(
struct
rfcomm_dev
*
dev
)
{
struct
tty_struct
*
tty
=
dev
->
tty
;
struct
sk_buff
*
skb
;
int
inserted
=
0
;
if
(
!
tty
)
return
;
BT_DBG
(
"dev %p tty %p"
,
dev
,
tty
);
rfcomm_dlc_lock
(
dev
->
dlc
);
while
((
skb
=
skb_dequeue
(
&
dev
->
pending
)))
{
inserted
+=
tty_insert_flip_string
(
tty
,
skb
->
data
,
skb
->
len
);
kfree_skb
(
skb
);
}
rfcomm_dlc_unlock
(
dev
->
dlc
);
if
(
inserted
>
0
)
tty_flip_buffer_push
(
tty
);
}
static
int
rfcomm_tty_open
(
struct
tty_struct
*
tty
,
struct
file
*
filp
)
static
int
rfcomm_tty_open
(
struct
tty_struct
*
tty
,
struct
file
*
filp
)
{
{
DECLARE_WAITQUEUE
(
wait
,
current
);
DECLARE_WAITQUEUE
(
wait
,
current
);
...
@@ -689,6 +741,10 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
...
@@ -689,6 +741,10 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
if
(
err
==
0
)
if
(
err
==
0
)
device_move
(
dev
->
tty_dev
,
rfcomm_get_device
(
dev
));
device_move
(
dev
->
tty_dev
,
rfcomm_get_device
(
dev
));
rfcomm_tty_copy_pending
(
dev
);
rfcomm_dlc_unthrottle
(
dev
->
dlc
);
return
err
;
return
err
;
}
}
...
@@ -1121,6 +1177,7 @@ int rfcomm_init_ttys(void)
...
@@ -1121,6 +1177,7 @@ int rfcomm_init_ttys(void)
rfcomm_tty_driver
->
flags
=
TTY_DRIVER_REAL_RAW
|
TTY_DRIVER_DYNAMIC_DEV
;
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
=
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
|
CLOCAL
;
rfcomm_tty_driver
->
init_termios
.
c_lflag
&=
~
ICANON
;
tty_set_operations
(
rfcomm_tty_driver
,
&
rfcomm_ops
);
tty_set_operations
(
rfcomm_tty_driver
,
&
rfcomm_ops
);
if
(
tty_register_driver
(
rfcomm_tty_driver
))
{
if
(
tty_register_driver
(
rfcomm_tty_driver
))
{
...
...
net/bluetooth/sco.c
View file @
407d819c
...
@@ -53,7 +53,9 @@
...
@@ -53,7 +53,9 @@
#define BT_DBG(D...)
#define BT_DBG(D...)
#endif
#endif
#define VERSION "0.5"
#define VERSION "0.6"
static
int
disable_esco
=
0
;
static
const
struct
proto_ops
sco_sock_ops
;
static
const
struct
proto_ops
sco_sock_ops
;
...
@@ -193,7 +195,10 @@ static int sco_connect(struct sock *sk)
...
@@ -193,7 +195,10 @@ static int sco_connect(struct sock *sk)
err
=
-
ENOMEM
;
err
=
-
ENOMEM
;
type
=
lmp_esco_capable
(
hdev
)
?
ESCO_LINK
:
SCO_LINK
;
if
(
lmp_esco_capable
(
hdev
)
&&
!
disable_esco
)
type
=
ESCO_LINK
;
else
type
=
SCO_LINK
;
hcon
=
hci_connect
(
hdev
,
type
,
dst
);
hcon
=
hci_connect
(
hdev
,
type
,
dst
);
if
(
!
hcon
)
if
(
!
hcon
)
...
@@ -921,7 +926,7 @@ static const struct proto_ops sco_sock_ops = {
...
@@ -921,7 +926,7 @@ static const struct proto_ops sco_sock_ops = {
.
sendmsg
=
sco_sock_sendmsg
,
.
sendmsg
=
sco_sock_sendmsg
,
.
recvmsg
=
bt_sock_recvmsg
,
.
recvmsg
=
bt_sock_recvmsg
,
.
poll
=
bt_sock_poll
,
.
poll
=
bt_sock_poll
,
.
ioctl
=
sock_no
_ioctl
,
.
ioctl
=
bt_sock
_ioctl
,
.
mmap
=
sock_no_mmap
,
.
mmap
=
sock_no_mmap
,
.
socketpair
=
sock_no_socketpair
,
.
socketpair
=
sock_no_socketpair
,
.
shutdown
=
sock_no_shutdown
,
.
shutdown
=
sock_no_shutdown
,
...
@@ -994,6 +999,9 @@ static void __exit sco_exit(void)
...
@@ -994,6 +999,9 @@ static void __exit sco_exit(void)
module_init
(
sco_init
);
module_init
(
sco_init
);
module_exit
(
sco_exit
);
module_exit
(
sco_exit
);
module_param
(
disable_esco
,
bool
,
0644
);
MODULE_PARM_DESC
(
disable_esco
,
"Disable eSCO connection creation"
);
MODULE_AUTHOR
(
"Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>"
);
MODULE_AUTHOR
(
"Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>"
);
MODULE_DESCRIPTION
(
"Bluetooth SCO ver "
VERSION
);
MODULE_DESCRIPTION
(
"Bluetooth SCO ver "
VERSION
);
MODULE_VERSION
(
VERSION
);
MODULE_VERSION
(
VERSION
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment