Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
9662cbc7
Commit
9662cbc7
authored
Dec 19, 2011
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next
parents
640f5950
4b0b2f08
Changes
15
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
1015 additions
and
975 deletions
+1015
-975
include/net/bluetooth/hci.h
include/net/bluetooth/hci.h
+9
-0
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_core.h
+57
-61
include/net/bluetooth/l2cap.h
include/net/bluetooth/l2cap.h
+13
-11
include/net/bluetooth/mgmt.h
include/net/bluetooth/mgmt.h
+108
-83
net/bluetooth/hci_conn.c
net/bluetooth/hci_conn.c
+59
-78
net/bluetooth/hci_core.c
net/bluetooth/hci_core.c
+95
-78
net/bluetooth/hci_event.c
net/bluetooth/hci_event.c
+64
-35
net/bluetooth/hci_sock.c
net/bluetooth/hci_sock.c
+12
-9
net/bluetooth/hci_sysfs.c
net/bluetooth/hci_sysfs.c
+37
-54
net/bluetooth/hidp/core.c
net/bluetooth/hidp/core.c
+2
-2
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_core.c
+189
-171
net/bluetooth/l2cap_sock.c
net/bluetooth/l2cap_sock.c
+4
-58
net/bluetooth/mgmt.c
net/bluetooth/mgmt.c
+363
-333
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/core.c
+1
-0
net/bluetooth/sco.c
net/bluetooth/sco.c
+2
-2
No files found.
include/net/bluetooth/hci.h
View file @
9662cbc7
...
@@ -210,6 +210,7 @@ enum {
...
@@ -210,6 +210,7 @@ enum {
#define LMP_EV4 0x01
#define LMP_EV4 0x01
#define LMP_EV5 0x02
#define LMP_EV5 0x02
#define LMP_NO_BREDR 0x20
#define LMP_LE 0x40
#define LMP_LE 0x40
#define LMP_SNIFF_SUBR 0x02
#define LMP_SNIFF_SUBR 0x02
...
@@ -745,6 +746,14 @@ struct hci_rp_read_bd_addr {
...
@@ -745,6 +746,14 @@ struct hci_rp_read_bd_addr {
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
}
__packed
;
}
__packed
;
#define HCI_OP_READ_DATA_BLOCK_SIZE 0x100a
struct
hci_rp_read_data_block_size
{
__u8
status
;
__le16
max_acl_len
;
__le16
block_len
;
__le16
num_blocks
;
}
__packed
;
#define HCI_OP_WRITE_PAGE_SCAN_ACTIVITY 0x0c1c
#define HCI_OP_WRITE_PAGE_SCAN_ACTIVITY 0x0c1c
struct
hci_cp_write_page_scan_activity
{
struct
hci_cp_write_page_scan_activity
{
__le16
interval
;
__le16
interval
;
...
...
include/net/bluetooth/hci_core.h
View file @
9662cbc7
...
@@ -61,18 +61,11 @@ struct inquiry_cache {
...
@@ -61,18 +61,11 @@ struct inquiry_cache {
struct
hci_conn_hash
{
struct
hci_conn_hash
{
struct
list_head
list
;
struct
list_head
list
;
spinlock_t
lock
;
unsigned
int
acl_num
;
unsigned
int
acl_num
;
unsigned
int
sco_num
;
unsigned
int
sco_num
;
unsigned
int
le_num
;
unsigned
int
le_num
;
};
};
struct
hci_chan_hash
{
struct
list_head
list
;
spinlock_t
lock
;
unsigned
int
num
;
};
struct
bdaddr_list
{
struct
bdaddr_list
{
struct
list_head
list
;
struct
list_head
list
;
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
...
@@ -124,7 +117,7 @@ struct adv_entry {
...
@@ -124,7 +117,7 @@ struct adv_entry {
#define NUM_REASSEMBLY 4
#define NUM_REASSEMBLY 4
struct
hci_dev
{
struct
hci_dev
{
struct
list_head
list
;
struct
list_head
list
;
s
pinlock_t
lock
;
s
truct
mutex
lock
;
atomic_t
refcnt
;
atomic_t
refcnt
;
char
name
[
8
];
char
name
[
8
];
...
@@ -188,6 +181,11 @@ struct hci_dev {
...
@@ -188,6 +181,11 @@ struct hci_dev {
unsigned
int
sco_pkts
;
unsigned
int
sco_pkts
;
unsigned
int
le_pkts
;
unsigned
int
le_pkts
;
__u16
block_len
;
__u16
block_mtu
;
__u16
num_blocks
;
__u16
block_cnt
;
unsigned
long
acl_last_tx
;
unsigned
long
acl_last_tx
;
unsigned
long
sco_last_tx
;
unsigned
long
sco_last_tx
;
unsigned
long
le_last_tx
;
unsigned
long
le_last_tx
;
...
@@ -200,10 +198,13 @@ struct hci_dev {
...
@@ -200,10 +198,13 @@ struct hci_dev {
__u16
discov_timeout
;
__u16
discov_timeout
;
struct
delayed_work
discov_off
;
struct
delayed_work
discov_off
;
struct
delayed_work
service_cache
;
struct
timer_list
cmd_timer
;
struct
timer_list
cmd_timer
;
struct
tasklet_struct
cmd_task
;
struct
tasklet_struct
rx_task
;
struct
work_struct
rx_work
;
struct
tasklet_struct
tx_task
;
struct
work_struct
cmd_work
;
struct
work_struct
tx_work
;
struct
sk_buff_head
rx_q
;
struct
sk_buff_head
rx_q
;
struct
sk_buff_head
raw_q
;
struct
sk_buff_head
raw_q
;
...
@@ -232,7 +233,7 @@ struct hci_dev {
...
@@ -232,7 +233,7 @@ struct hci_dev {
struct
list_head
remote_oob_data
;
struct
list_head
remote_oob_data
;
struct
list_head
adv_entries
;
struct
list_head
adv_entries
;
struct
timer_list
adv_timer
;
struct
delayed_work
adv_work
;
struct
hci_dev_stats
stat
;
struct
hci_dev_stats
stat
;
...
@@ -301,15 +302,12 @@ struct hci_conn {
...
@@ -301,15 +302,12 @@ struct hci_conn {
unsigned
int
sent
;
unsigned
int
sent
;
struct
sk_buff_head
data_q
;
struct
sk_buff_head
data_q
;
struct
hci_chan_hash
chan_hash
;
struct
list_head
chan_list
;
struct
timer_list
disc_timer
;
struct
delayed_work
disc_work
;
struct
timer_list
idle_timer
;
struct
timer_list
idle_timer
;
struct
timer_list
auto_accept_timer
;
struct
timer_list
auto_accept_timer
;
struct
work_struct
work_add
;
struct
work_struct
work_del
;
struct
device
dev
;
struct
device
dev
;
atomic_t
devref
;
atomic_t
devref
;
...
@@ -390,15 +388,15 @@ static inline void hci_conn_hash_init(struct hci_dev *hdev)
...
@@ -390,15 +388,15 @@ static inline void hci_conn_hash_init(struct hci_dev *hdev)
{
{
struct
hci_conn_hash
*
h
=
&
hdev
->
conn_hash
;
struct
hci_conn_hash
*
h
=
&
hdev
->
conn_hash
;
INIT_LIST_HEAD
(
&
h
->
list
);
INIT_LIST_HEAD
(
&
h
->
list
);
spin_lock_init
(
&
h
->
lock
);
h
->
acl_num
=
0
;
h
->
acl_num
=
0
;
h
->
sco_num
=
0
;
h
->
sco_num
=
0
;
h
->
le_num
=
0
;
}
}
static
inline
void
hci_conn_hash_add
(
struct
hci_dev
*
hdev
,
struct
hci_conn
*
c
)
static
inline
void
hci_conn_hash_add
(
struct
hci_dev
*
hdev
,
struct
hci_conn
*
c
)
{
{
struct
hci_conn_hash
*
h
=
&
hdev
->
conn_hash
;
struct
hci_conn_hash
*
h
=
&
hdev
->
conn_hash
;
list_add
(
&
c
->
list
,
&
h
->
list
);
list_add
_rcu
(
&
c
->
list
,
&
h
->
list
);
switch
(
c
->
type
)
{
switch
(
c
->
type
)
{
case
ACL_LINK
:
case
ACL_LINK
:
h
->
acl_num
++
;
h
->
acl_num
++
;
...
@@ -416,7 +414,10 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
...
@@ -416,7 +414,10 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
static
inline
void
hci_conn_hash_del
(
struct
hci_dev
*
hdev
,
struct
hci_conn
*
c
)
static
inline
void
hci_conn_hash_del
(
struct
hci_dev
*
hdev
,
struct
hci_conn
*
c
)
{
{
struct
hci_conn_hash
*
h
=
&
hdev
->
conn_hash
;
struct
hci_conn_hash
*
h
=
&
hdev
->
conn_hash
;
list_del
(
&
c
->
list
);
list_del_rcu
(
&
c
->
list
);
synchronize_rcu
();
switch
(
c
->
type
)
{
switch
(
c
->
type
)
{
case
ACL_LINK
:
case
ACL_LINK
:
h
->
acl_num
--
;
h
->
acl_num
--
;
...
@@ -451,14 +452,18 @@ static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
...
@@ -451,14 +452,18 @@ static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
__u16
handle
)
__u16
handle
)
{
{
struct
hci_conn_hash
*
h
=
&
hdev
->
conn_hash
;
struct
hci_conn_hash
*
h
=
&
hdev
->
conn_hash
;
struct
list_head
*
p
;
struct
hci_conn
*
c
;
struct
hci_conn
*
c
;
list_for_each
(
p
,
&
h
->
list
)
{
rcu_read_lock
();
c
=
list_entry
(
p
,
struct
hci_conn
,
list
);
if
(
c
->
handle
==
handle
)
list_for_each_entry_rcu
(
c
,
&
h
->
list
,
list
)
{
if
(
c
->
handle
==
handle
)
{
rcu_read_unlock
();
return
c
;
return
c
;
}
}
}
rcu_read_unlock
();
return
NULL
;
return
NULL
;
}
}
...
@@ -466,14 +471,19 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
...
@@ -466,14 +471,19 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
__u8
type
,
bdaddr_t
*
ba
)
__u8
type
,
bdaddr_t
*
ba
)
{
{
struct
hci_conn_hash
*
h
=
&
hdev
->
conn_hash
;
struct
hci_conn_hash
*
h
=
&
hdev
->
conn_hash
;
struct
list_head
*
p
;
struct
hci_conn
*
c
;
struct
hci_conn
*
c
;
list_for_each
(
p
,
&
h
->
list
)
{
rcu_read_lock
();
c
=
list_entry
(
p
,
struct
hci_conn
,
list
);
if
(
c
->
type
==
type
&&
!
bacmp
(
&
c
->
dst
,
ba
))
list_for_each_entry_rcu
(
c
,
&
h
->
list
,
list
)
{
if
(
c
->
type
==
type
&&
!
bacmp
(
&
c
->
dst
,
ba
))
{
rcu_read_unlock
();
return
c
;
return
c
;
}
}
}
rcu_read_unlock
();
return
NULL
;
return
NULL
;
}
}
...
@@ -481,37 +491,20 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
...
@@ -481,37 +491,20 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
__u8
type
,
__u16
state
)
__u8
type
,
__u16
state
)
{
{
struct
hci_conn_hash
*
h
=
&
hdev
->
conn_hash
;
struct
hci_conn_hash
*
h
=
&
hdev
->
conn_hash
;
struct
list_head
*
p
;
struct
hci_conn
*
c
;
struct
hci_conn
*
c
;
list_for_each
(
p
,
&
h
->
list
)
{
rcu_read_lock
();
c
=
list_entry
(
p
,
struct
hci_conn
,
list
);
if
(
c
->
type
==
type
&&
c
->
state
==
state
)
list_for_each_entry_rcu
(
c
,
&
h
->
list
,
list
)
{
if
(
c
->
type
==
type
&&
c
->
state
==
state
)
{
rcu_read_unlock
();
return
c
;
return
c
;
}
}
return
NULL
;
}
}
static
inline
void
hci_chan_hash_init
(
struct
hci_conn
*
c
)
{
struct
hci_chan_hash
*
h
=
&
c
->
chan_hash
;
INIT_LIST_HEAD
(
&
h
->
list
);
spin_lock_init
(
&
h
->
lock
);
h
->
num
=
0
;
}
static
inline
void
hci_chan_hash_add
(
struct
hci_conn
*
c
,
struct
hci_chan
*
chan
)
rcu_read_unlock
();
{
struct
hci_chan_hash
*
h
=
&
c
->
chan_hash
;
list_add
(
&
chan
->
list
,
&
h
->
list
);
h
->
num
++
;
}
static
inline
void
hci_chan_hash_del
(
struct
hci_conn
*
c
,
struct
hci_chan
*
chan
)
return
NULL
;
{
struct
hci_chan_hash
*
h
=
&
c
->
chan_hash
;
list_del
(
&
chan
->
list
);
h
->
num
--
;
}
}
void
hci_acl_connect
(
struct
hci_conn
*
conn
);
void
hci_acl_connect
(
struct
hci_conn
*
conn
);
...
@@ -527,7 +520,7 @@ void hci_conn_check_pending(struct hci_dev *hdev);
...
@@ -527,7 +520,7 @@ void hci_conn_check_pending(struct hci_dev *hdev);
struct
hci_chan
*
hci_chan_create
(
struct
hci_conn
*
conn
);
struct
hci_chan
*
hci_chan_create
(
struct
hci_conn
*
conn
);
int
hci_chan_del
(
struct
hci_chan
*
chan
);
int
hci_chan_del
(
struct
hci_chan
*
chan
);
void
hci_chan_
hash
_flush
(
struct
hci_conn
*
conn
);
void
hci_chan_
list
_flush
(
struct
hci_conn
*
conn
);
struct
hci_conn
*
hci_connect
(
struct
hci_dev
*
hdev
,
int
type
,
bdaddr_t
*
dst
,
struct
hci_conn
*
hci_connect
(
struct
hci_dev
*
hdev
,
int
type
,
bdaddr_t
*
dst
,
__u8
sec_level
,
__u8
auth_type
);
__u8
sec_level
,
__u8
auth_type
);
...
@@ -538,7 +531,6 @@ int hci_conn_change_link_key(struct hci_conn *conn);
...
@@ -538,7 +531,6 @@ int hci_conn_change_link_key(struct hci_conn *conn);
int
hci_conn_switch_role
(
struct
hci_conn
*
conn
,
__u8
role
);
int
hci_conn_switch_role
(
struct
hci_conn
*
conn
,
__u8
role
);
void
hci_conn_enter_active_mode
(
struct
hci_conn
*
conn
,
__u8
force_active
);
void
hci_conn_enter_active_mode
(
struct
hci_conn
*
conn
,
__u8
force_active
);
void
hci_conn_enter_sniff_mode
(
struct
hci_conn
*
conn
);
void
hci_conn_hold_device
(
struct
hci_conn
*
conn
);
void
hci_conn_hold_device
(
struct
hci_conn
*
conn
);
void
hci_conn_put_device
(
struct
hci_conn
*
conn
);
void
hci_conn_put_device
(
struct
hci_conn
*
conn
);
...
@@ -546,7 +538,7 @@ void hci_conn_put_device(struct hci_conn *conn);
...
@@ -546,7 +538,7 @@ void hci_conn_put_device(struct hci_conn *conn);
static
inline
void
hci_conn_hold
(
struct
hci_conn
*
conn
)
static
inline
void
hci_conn_hold
(
struct
hci_conn
*
conn
)
{
{
atomic_inc
(
&
conn
->
refcnt
);
atomic_inc
(
&
conn
->
refcnt
);
del_timer
(
&
conn
->
disc_timer
);
cancel_delayed_work_sync
(
&
conn
->
disc_work
);
}
}
static
inline
void
hci_conn_put
(
struct
hci_conn
*
conn
)
static
inline
void
hci_conn_put
(
struct
hci_conn
*
conn
)
...
@@ -565,7 +557,9 @@ static inline void hci_conn_put(struct hci_conn *conn)
...
@@ -565,7 +557,9 @@ static inline void hci_conn_put(struct hci_conn *conn)
}
else
{
}
else
{
timeo
=
msecs_to_jiffies
(
10
);
timeo
=
msecs_to_jiffies
(
10
);
}
}
mod_timer
(
&
conn
->
disc_timer
,
jiffies
+
timeo
);
cancel_delayed_work_sync
(
&
conn
->
disc_work
);
queue_delayed_work
(
conn
->
hdev
->
workqueue
,
&
conn
->
disc_work
,
jiffies
+
timeo
);
}
}
}
}
...
@@ -597,10 +591,8 @@ static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d)
...
@@ -597,10 +591,8 @@ static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d)
try_module_get(d->owner) ? __hci_dev_hold(d) : NULL; \
try_module_get(d->owner) ? __hci_dev_hold(d) : NULL; \
})
})
#define hci_dev_lock(d) spin_lock(&d->lock)
#define hci_dev_lock(d) mutex_lock(&d->lock)
#define hci_dev_unlock(d) spin_unlock(&d->lock)
#define hci_dev_unlock(d) mutex_unlock(&d->lock)
#define hci_dev_lock_bh(d) spin_lock_bh(&d->lock)
#define hci_dev_unlock_bh(d) spin_unlock_bh(&d->lock)
struct
hci_dev
*
hci_dev_get
(
int
index
);
struct
hci_dev
*
hci_dev_get
(
int
index
);
struct
hci_dev
*
hci_get_route
(
bdaddr_t
*
src
,
bdaddr_t
*
dst
);
struct
hci_dev
*
hci_get_route
(
bdaddr_t
*
src
,
bdaddr_t
*
dst
);
...
@@ -960,12 +952,16 @@ int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
...
@@ -960,12 +952,16 @@ int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
/* HCI info for socket */
/* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk)
#define hci_pi(sk) ((struct hci_pinfo *) sk)
/* HCI socket flags */
#define HCI_PI_MGMT_INIT 0
struct
hci_pinfo
{
struct
hci_pinfo
{
struct
bt_sock
bt
;
struct
bt_sock
bt
;
struct
hci_dev
*
hdev
;
struct
hci_dev
*
hdev
;
struct
hci_filter
filter
;
struct
hci_filter
filter
;
__u32
cmsg_mask
;
__u32
cmsg_mask
;
unsigned
short
channel
;
unsigned
short
channel
;
unsigned
long
flags
;
};
};
/* HCI security filter */
/* HCI security filter */
...
...
include/net/bluetooth/l2cap.h
View file @
9662cbc7
...
@@ -482,10 +482,11 @@ struct l2cap_chan {
...
@@ -482,10 +482,11 @@ struct l2cap_chan {
__u32
remote_acc_lat
;
__u32
remote_acc_lat
;
__u32
remote_flush_to
;
__u32
remote_flush_to
;
struct
timer_list
chan_timer
;
struct
delayed_work
chan_timer
;
struct
timer_list
retrans_timer
;
struct
delayed_work
retrans_timer
;
struct
timer_list
monitor_timer
;
struct
delayed_work
monitor_timer
;
struct
timer_list
ack_timer
;
struct
delayed_work
ack_timer
;
struct
sk_buff
*
tx_send_head
;
struct
sk_buff
*
tx_send_head
;
struct
sk_buff_head
tx_q
;
struct
sk_buff_head
tx_q
;
struct
sk_buff_head
srej_q
;
struct
sk_buff_head
srej_q
;
...
@@ -521,7 +522,7 @@ struct l2cap_conn {
...
@@ -521,7 +522,7 @@ struct l2cap_conn {
__u8
info_state
;
__u8
info_state
;
__u8
info_ident
;
__u8
info_ident
;
struct
timer_list
info_timer
;
struct
delayed_work
info_work
;
spinlock_t
lock
;
spinlock_t
lock
;
...
@@ -535,7 +536,7 @@ struct l2cap_conn {
...
@@ -535,7 +536,7 @@ struct l2cap_conn {
struct
smp_chan
*
smp_chan
;
struct
smp_chan
*
smp_chan
;
struct
list_head
chan_l
;
struct
list_head
chan_l
;
rwlock_t
chan_lock
;
struct
mutex
chan_lock
;
};
};
#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01
#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01
...
@@ -595,16 +596,16 @@ enum {
...
@@ -595,16 +596,16 @@ enum {
};
};
#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
#define __clear_chan_timer(c) l2cap_clear_timer(
c,
&c->chan_timer)
#define __clear_chan_timer(c) l2cap_clear_timer(&c->chan_timer)
#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
L2CAP_DEFAULT_RETRANS_TO);
L2CAP_DEFAULT_RETRANS_TO);
#define __clear_retrans_timer(c) l2cap_clear_timer(
c,
&c->retrans_timer)
#define __clear_retrans_timer(c) l2cap_clear_timer(&c->retrans_timer)
#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \
#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \
L2CAP_DEFAULT_MONITOR_TO);
L2CAP_DEFAULT_MONITOR_TO);
#define __clear_monitor_timer(c) l2cap_clear_timer(
c,
&c->monitor_timer)
#define __clear_monitor_timer(c) l2cap_clear_timer(&c->monitor_timer)
#define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \
#define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \
L2CAP_DEFAULT_ACK_TO);
L2CAP_DEFAULT_ACK_TO);
#define __clear_ack_timer(c) l2cap_clear_timer(
c,
&c->ack_timer)
#define __clear_ack_timer(c) l2cap_clear_timer(&c->ack_timer)
static
inline
int
__seq_offset
(
struct
l2cap_chan
*
chan
,
__u16
seq1
,
__u16
seq2
)
static
inline
int
__seq_offset
(
struct
l2cap_chan
*
chan
,
__u16
seq1
,
__u16
seq2
)
{
{
...
@@ -805,7 +806,8 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid);
...
@@ -805,7 +806,8 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid);
struct
l2cap_chan
*
l2cap_chan_create
(
struct
sock
*
sk
);
struct
l2cap_chan
*
l2cap_chan_create
(
struct
sock
*
sk
);
void
l2cap_chan_close
(
struct
l2cap_chan
*
chan
,
int
reason
);
void
l2cap_chan_close
(
struct
l2cap_chan
*
chan
,
int
reason
);
void
l2cap_chan_destroy
(
struct
l2cap_chan
*
chan
);
void
l2cap_chan_destroy
(
struct
l2cap_chan
*
chan
);
int
l2cap_chan_connect
(
struct
l2cap_chan
*
chan
);
inline
int
l2cap_chan_connect
(
struct
l2cap_chan
*
chan
,
__le16
psm
,
u16
cid
,
bdaddr_t
*
dst
);
int
l2cap_chan_send
(
struct
l2cap_chan
*
chan
,
struct
msghdr
*
msg
,
size_t
len
,
int
l2cap_chan_send
(
struct
l2cap_chan
*
chan
,
struct
msghdr
*
msg
,
size_t
len
,
u32
priority
);
u32
priority
);
void
l2cap_chan_busy
(
struct
l2cap_chan
*
chan
,
int
busy
);
void
l2cap_chan_busy
(
struct
l2cap_chan
*
chan
,
int
busy
);
...
...
include/net/bluetooth/mgmt.h
View file @
9662cbc7
...
@@ -61,22 +61,29 @@ struct mgmt_rp_read_index_list {
...
@@ -61,22 +61,29 @@ struct mgmt_rp_read_index_list {
/* Reserve one extra byte for names in management messages so that they
/* Reserve one extra byte for names in management messages so that they
* are always guaranteed to be nul-terminated */
* are always guaranteed to be nul-terminated */
#define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1)
#define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1)
#define MGMT_MAX_SHORT_NAME_LENGTH (10 + 1)
#define MGMT_SETTING_POWERED 0x00000001
#define MGMT_SETTING_CONNECTABLE 0x00000002
#define MGMT_SETTING_FAST_CONNECTABLE 0x00000004
#define MGMT_SETTING_DISCOVERABLE 0x00000008
#define MGMT_SETTING_PAIRABLE 0x00000010
#define MGMT_SETTING_LINK_SECURITY 0x00000020
#define MGMT_SETTING_SSP 0x00000040
#define MGMT_SETTING_BREDR 0x00000080
#define MGMT_SETTING_HS 0x00000100
#define MGMT_SETTING_LE 0x00000200
#define MGMT_OP_READ_INFO 0x0004
#define MGMT_OP_READ_INFO 0x0004
struct
mgmt_rp_read_info
{
struct
mgmt_rp_read_info
{
__u8
type
;
__u8
powered
;
__u8
connectable
;
__u8
discoverable
;
__u8
pairable
;
__u8
sec_mode
;
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
__u8
version
;
__le16
manufacturer
;
__le32
supported_settings
;
__le32
current_settings
;
__u8
dev_class
[
3
];
__u8
dev_class
[
3
];
__u8
features
[
8
];
__u16
manufacturer
;
__u8
hci_ver
;
__u16
hci_rev
;
__u8
name
[
MGMT_MAX_NAME_LENGTH
];
__u8
name
[
MGMT_MAX_NAME_LENGTH
];
__u8
short_name
[
MGMT_MAX_SHORT_NAME_LENGTH
];
}
__packed
;
}
__packed
;
struct
mgmt_mode
{
struct
mgmt_mode
{
...
@@ -93,28 +100,38 @@ struct mgmt_cp_set_discoverable {
...
@@ -93,28 +100,38 @@ struct mgmt_cp_set_discoverable {
#define MGMT_OP_SET_CONNECTABLE 0x0007
#define MGMT_OP_SET_CONNECTABLE 0x0007
#define MGMT_OP_SET_
PAIRABLE
0x0008
#define MGMT_OP_SET_
FAST_CONNECTABLE
0x0008
#define MGMT_OP_ADD_UUID 0x0009
#define MGMT_OP_SET_PAIRABLE 0x0009
struct
mgmt_cp_add_uuid
{
__u8
uuid
[
16
];
__u8
svc_hint
;
}
__packed
;
#define MGMT_OP_REMOVE_UUID 0x000A
#define MGMT_OP_SET_LINK_SECURITY 0x000A
struct
mgmt_cp_remove_uuid
{
__u8
uuid
[
16
];
}
__packed
;
#define MGMT_OP_SET_DEV_CLASS 0x000B
#define MGMT_OP_SET_SSP 0x000B
#define MGMT_OP_SET_HS 0x000C
#define MGMT_OP_SET_LE 0x000D
#define MGMT_OP_SET_DEV_CLASS 0x000E
struct
mgmt_cp_set_dev_class
{
struct
mgmt_cp_set_dev_class
{
__u8
major
;
__u8
major
;
__u8
minor
;
__u8
minor
;
}
__packed
;
}
__packed
;
#define MGMT_OP_SET_SERVICE_CACHE 0x000C
#define MGMT_OP_SET_LOCAL_NAME 0x000F
struct
mgmt_cp_set_service_cache
{
struct
mgmt_cp_set_local_name
{
__u8
enable
;
__u8
name
[
MGMT_MAX_NAME_LENGTH
];
}
__packed
;
#define MGMT_OP_ADD_UUID 0x0010
struct
mgmt_cp_add_uuid
{
__u8
uuid
[
16
];
__u8
svc_hint
;
}
__packed
;
#define MGMT_OP_REMOVE_UUID 0x0011
struct
mgmt_cp_remove_uuid
{
__u8
uuid
[
16
];
}
__packed
;
}
__packed
;
struct
mgmt_link_key_info
{
struct
mgmt_link_key_info
{
...
@@ -124,14 +141,14 @@ struct mgmt_link_key_info {
...
@@ -124,14 +141,14 @@ struct mgmt_link_key_info {
u8
pin_len
;
u8
pin_len
;
}
__packed
;
}
__packed
;
#define MGMT_OP_LOAD_LINK_KEYS 0x00
0D
#define MGMT_OP_LOAD_LINK_KEYS 0x00
12
struct
mgmt_cp_load_link_keys
{
struct
mgmt_cp_load_link_keys
{
__u8
debug_keys
;
__u8
debug_keys
;
__le16
key_count
;
__le16
key_count
;
struct
mgmt_link_key_info
keys
[
0
];
struct
mgmt_link_key_info
keys
[
0
];
}
__packed
;
}
__packed
;
#define MGMT_OP_REMOVE_KEYS 0x00
0E
#define MGMT_OP_REMOVE_KEYS 0x00
13
struct
mgmt_cp_remove_keys
{
struct
mgmt_cp_remove_keys
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
__u8
disconnect
;
__u8
disconnect
;
...
@@ -141,7 +158,7 @@ struct mgmt_rp_remove_keys {
...
@@ -141,7 +158,7 @@ struct mgmt_rp_remove_keys {
__u8
status
;
__u8
status
;
};
};
#define MGMT_OP_DISCONNECT 0x00
0F
#define MGMT_OP_DISCONNECT 0x00
14
struct
mgmt_cp_disconnect
{
struct
mgmt_cp_disconnect
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
}
__packed
;
}
__packed
;
...
@@ -160,13 +177,13 @@ struct mgmt_addr_info {
...
@@ -160,13 +177,13 @@ struct mgmt_addr_info {
__u8
type
;
__u8
type
;
}
__packed
;
}
__packed
;
#define MGMT_OP_GET_CONNECTIONS 0x001
0
#define MGMT_OP_GET_CONNECTIONS 0x001
5
struct
mgmt_rp_get_connections
{
struct
mgmt_rp_get_connections
{
__le16
conn_count
;
__le16
conn_count
;
struct
mgmt_addr_info
addr
[
0
];
struct
mgmt_addr_info
addr
[
0
];
}
__packed
;
}
__packed
;
#define MGMT_OP_PIN_CODE_REPLY 0x001
1
#define MGMT_OP_PIN_CODE_REPLY 0x001
6
struct
mgmt_cp_pin_code_reply
{
struct
mgmt_cp_pin_code_reply
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
__u8
pin_len
;
__u8
pin_len
;
...
@@ -177,17 +194,17 @@ struct mgmt_rp_pin_code_reply {
...
@@ -177,17 +194,17 @@ struct mgmt_rp_pin_code_reply {
uint8_t
status
;
uint8_t
status
;
}
__packed
;
}
__packed
;
#define MGMT_OP_PIN_CODE_NEG_REPLY 0x001
2
#define MGMT_OP_PIN_CODE_NEG_REPLY 0x001
7
struct
mgmt_cp_pin_code_neg_reply
{
struct
mgmt_cp_pin_code_neg_reply
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
}
__packed
;
}
__packed
;
#define MGMT_OP_SET_IO_CAPABILITY 0x001
3
#define MGMT_OP_SET_IO_CAPABILITY 0x001
8
struct
mgmt_cp_set_io_capability
{
struct
mgmt_cp_set_io_capability
{
__u8
io_capability
;
__u8
io_capability
;
}
__packed
;
}
__packed
;
#define MGMT_OP_PAIR_DEVICE 0x001
4
#define MGMT_OP_PAIR_DEVICE 0x001
9
struct
mgmt_cp_pair_device
{
struct
mgmt_cp_pair_device
{
struct
mgmt_addr_info
addr
;
struct
mgmt_addr_info
addr
;
__u8
io_cap
;
__u8
io_cap
;
...
@@ -197,7 +214,7 @@ struct mgmt_rp_pair_device {
...
@@ -197,7 +214,7 @@ struct mgmt_rp_pair_device {
__u8
status
;
__u8
status
;
}
__packed
;
}
__packed
;
#define MGMT_OP_USER_CONFIRM_REPLY 0x001
5
#define MGMT_OP_USER_CONFIRM_REPLY 0x001
A
struct
mgmt_cp_user_confirm_reply
{
struct
mgmt_cp_user_confirm_reply
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
}
__packed
;
}
__packed
;
...
@@ -206,61 +223,68 @@ struct mgmt_rp_user_confirm_reply {
...
@@ -206,61 +223,68 @@ struct mgmt_rp_user_confirm_reply {
__u8
status
;
__u8
status
;
}
__packed
;
}
__packed
;
#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x0016
#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001B
struct
mgmt_cp_user_confirm_neg_reply
{
bdaddr_t
bdaddr
;
}
__packed
;
#define MGMT_OP_SET_LOCAL_NAME 0x0017
#define MGMT_OP_USER_PASSKEY_REPLY 0x001C
struct
mgmt_cp_set_local_name
{
struct
mgmt_cp_user_passkey_reply
{
__u8
name
[
MGMT_MAX_NAME_LENGTH
];
bdaddr_t
bdaddr
;
__le32
passkey
;
}
__packed
;
struct
mgmt_rp_user_passkey_reply
{
bdaddr_t
bdaddr
;
__u8
status
;
}
__packed
;
}
__packed
;
#define MGMT_OP_READ_LOCAL_OOB_DATA 0x0018
#define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001D
struct
mgmt_cp_user_passkey_neg_reply
{
bdaddr_t
bdaddr
;
}
__packed
;
#define MGMT_OP_READ_LOCAL_OOB_DATA 0x001E
struct
mgmt_rp_read_local_oob_data
{
struct
mgmt_rp_read_local_oob_data
{
__u8
hash
[
16
];
__u8
hash
[
16
];
__u8
randomizer
[
16
];
__u8
randomizer
[
16
];
}
__packed
;
}
__packed
;
#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x001
9
#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x001
F
struct
mgmt_cp_add_remote_oob_data
{
struct
mgmt_cp_add_remote_oob_data
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
__u8
hash
[
16
];
__u8
hash
[
16
];
__u8
randomizer
[
16
];
__u8
randomizer
[
16
];
}
__packed
;
}
__packed
;
#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x00
1A
#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x00
20
struct
mgmt_cp_remove_remote_oob_data
{
struct
mgmt_cp_remove_remote_oob_data
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
}
__packed
;
}
__packed
;
#define MGMT_OP_START_DISCOVERY 0x00
1B
#define MGMT_OP_START_DISCOVERY 0x00
21
struct
mgmt_cp_start_discovery
{
struct
mgmt_cp_start_discovery
{
__u8
type
;
__u8
type
;
}
__packed
;
}
__packed
;
#define MGMT_OP_STOP_DISCOVERY 0x00
1C
#define MGMT_OP_STOP_DISCOVERY 0x00
22
#define MGMT_OP_
BLOCK_DEVICE 0x001D
#define MGMT_OP_
CONFIRM_NAME 0x0023
struct
mgmt_cp_
block_devic
e
{
struct
mgmt_cp_
confirm_nam
e
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
__u8
name_known
;
}
__packed
;
}
__packed
;
struct
mgmt_rp_confirm_name
{
#define MGMT_OP_UNBLOCK_DEVICE 0x001E
struct
mgmt_cp_unblock_device
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
__u8
status
;
}
__packed
;
}
__packed
;
#define MGMT_OP_SET_FAST_CONNECTABLE 0x001F
#define MGMT_OP_BLOCK_DEVICE 0x0024
struct
mgmt_cp_set_fast_connectable
{
struct
mgmt_cp_block_device
{
__u8
enable
;
}
__packed
;
#define MGMT_OP_USER_PASSKEY_REPLY 0x0020
struct
mgmt_cp_user_passkey_reply
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
__le32
passkey
;
}
__packed
;
}
__packed
;
#define MGMT_OP_U
SER_PASSKEY_NEG_REPLY 0x0021
#define MGMT_OP_U
NBLOCK_DEVICE 0x0025
struct
mgmt_cp_u
ser_passkey_neg_reply
{
struct
mgmt_cp_u
nblock_device
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
}
__packed
;
}
__packed
;
...
@@ -285,81 +309,82 @@ struct mgmt_ev_controller_error {
...
@@ -285,81 +309,82 @@ struct mgmt_ev_controller_error {
#define MGMT_EV_INDEX_REMOVED 0x0005
#define MGMT_EV_INDEX_REMOVED 0x0005
#define MGMT_EV_
POWERED
0x0006
#define MGMT_EV_
NEW_SETTINGS
0x0006
#define MGMT_EV_DISCOVERABLE 0x0007
#define MGMT_EV_CLASS_OF_DEV_CHANGED 0x0007
struct
mgmt_ev_class_of_dev_changed
{
#define MGMT_EV_CONNECTABLE 0x0008
__u8
dev_class
[
3
];
};
#define MGMT_EV_PAIRABLE 0x0009
#define MGMT_EV_LOCAL_NAME_CHANGED 0x0008
struct
mgmt_ev_local_name_changed
{
__u8
name
[
MGMT_MAX_NAME_LENGTH
];
__u8
short_name
[
MGMT_MAX_SHORT_NAME_LENGTH
];
}
__packed
;
#define MGMT_EV_NEW_LINK_KEY 0x000
A
#define MGMT_EV_NEW_LINK_KEY 0x000
9
struct
mgmt_ev_new_link_key
{
struct
mgmt_ev_new_link_key
{
__u8
store_hint
;
__u8
store_hint
;
struct
mgmt_link_key_info
key
;
struct
mgmt_link_key_info
key
;
}
__packed
;
}
__packed
;
#define MGMT_EV_CONNECTED 0x000
B
#define MGMT_EV_CONNECTED 0x000
A
#define MGMT_EV_DISCONNECTED 0x000
C
#define MGMT_EV_DISCONNECTED 0x000
B
#define MGMT_EV_CONNECT_FAILED 0x000
D
#define MGMT_EV_CONNECT_FAILED 0x000
C
struct
mgmt_ev_connect_failed
{
struct
mgmt_ev_connect_failed
{
struct
mgmt_addr_info
addr
;
struct
mgmt_addr_info
addr
;
__u8
status
;
__u8
status
;
}
__packed
;
}
__packed
;
#define MGMT_EV_PIN_CODE_REQUEST 0x000
E
#define MGMT_EV_PIN_CODE_REQUEST 0x000
D
struct
mgmt_ev_pin_code_request
{
struct
mgmt_ev_pin_code_request
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
__u8
secure
;
__u8
secure
;
}
__packed
;
}
__packed
;
#define MGMT_EV_USER_CONFIRM_REQUEST 0x000
F
#define MGMT_EV_USER_CONFIRM_REQUEST 0x000
E
struct
mgmt_ev_user_confirm_request
{
struct
mgmt_ev_user_confirm_request
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
__u8
confirm_hint
;
__u8
confirm_hint
;
__le32
value
;
__le32
value
;
}
__packed
;
}
__packed
;
#define MGMT_EV_USER_PASSKEY_REQUEST 0x000F
struct
mgmt_ev_user_passkey_request
{
bdaddr_t
bdaddr
;
}
__packed
;
#define MGMT_EV_AUTH_FAILED 0x0010
#define MGMT_EV_AUTH_FAILED 0x0010
struct
mgmt_ev_auth_failed
{
struct
mgmt_ev_auth_failed
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
__u8
status
;
__u8
status
;
}
__packed
;
}
__packed
;
#define MGMT_EV_LOCAL_NAME_CHANGED 0x0011
#define MGMT_EV_DEVICE_FOUND 0x0011
struct
mgmt_ev_local_name_changed
{
__u8
name
[
MGMT_MAX_NAME_LENGTH
];
}
__packed
;
#define MGMT_EV_DEVICE_FOUND 0x0012
struct
mgmt_ev_device_found
{
struct
mgmt_ev_device_found
{
struct
mgmt_addr_info
addr
;
struct
mgmt_addr_info
addr
;
__u8
dev_class
[
3
];
__u8
dev_class
[
3
];
__s8
rssi
;
__s8
rssi
;
__u8
confirm_name
;
__u8
eir
[
HCI_MAX_EIR_LENGTH
];
__u8
eir
[
HCI_MAX_EIR_LENGTH
];
}
__packed
;
}
__packed
;
#define MGMT_EV_REMOTE_NAME 0x001
3
#define MGMT_EV_REMOTE_NAME 0x001
2
struct
mgmt_ev_remote_name
{
struct
mgmt_ev_remote_name
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
__u8
name
[
MGMT_MAX_NAME_LENGTH
];
__u8
name
[
MGMT_MAX_NAME_LENGTH
];
}
__packed
;
}
__packed
;
#define MGMT_EV_DISCOVERING 0x001
4
#define MGMT_EV_DISCOVERING 0x001
3
#define MGMT_EV_DEVICE_BLOCKED 0x001
5
#define MGMT_EV_DEVICE_BLOCKED 0x001
4
struct
mgmt_ev_device_blocked
{
struct
mgmt_ev_device_blocked
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
}
__packed
;
}
__packed
;
#define MGMT_EV_DEVICE_UNBLOCKED 0x001
6
#define MGMT_EV_DEVICE_UNBLOCKED 0x001
5
struct
mgmt_ev_device_unblocked
{
struct
mgmt_ev_device_unblocked
{
bdaddr_t
bdaddr
;
bdaddr_t
bdaddr
;
}
__packed
;
}
__packed
;
#define MGMT_EV_USER_PASSKEY_REQUEST 0x0017
struct
mgmt_ev_user_passkey_request
{
bdaddr_t
bdaddr
;
}
__packed
;
net/bluetooth/hci_conn.c
View file @
9662cbc7
...
@@ -275,9 +275,10 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status)
...
@@ -275,9 +275,10 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status)
}
}
}
}
static
void
hci_conn_timeout
(
unsigned
long
arg
)
static
void
hci_conn_timeout
(
struct
work_struct
*
work
)
{
{
struct
hci_conn
*
conn
=
(
void
*
)
arg
;
struct
hci_conn
*
conn
=
container_of
(
work
,
struct
hci_conn
,
disc_work
.
work
);
struct
hci_dev
*
hdev
=
conn
->
hdev
;
struct
hci_dev
*
hdev
=
conn
->
hdev
;
__u8
reason
;
__u8
reason
;
...
@@ -311,6 +312,42 @@ static void hci_conn_timeout(unsigned long arg)
...
@@ -311,6 +312,42 @@ static void hci_conn_timeout(unsigned long arg)
hci_dev_unlock
(
hdev
);
hci_dev_unlock
(
hdev
);
}
}
/* Enter sniff mode */
static
void
hci_conn_enter_sniff_mode
(
struct
hci_conn
*
conn
)
{
struct
hci_dev
*
hdev
=
conn
->
hdev
;
BT_DBG
(
"conn %p mode %d"
,
conn
,
conn
->
mode
);
if
(
test_bit
(
HCI_RAW
,
&
hdev
->
flags
))
return
;
if
(
!
lmp_sniff_capable
(
hdev
)
||
!
lmp_sniff_capable
(
conn
))
return
;
if
(
conn
->
mode
!=
HCI_CM_ACTIVE
||
!
(
conn
->
link_policy
&
HCI_LP_SNIFF
))
return
;
if
(
lmp_sniffsubr_capable
(
hdev
)
&&
lmp_sniffsubr_capable
(
conn
))
{
struct
hci_cp_sniff_subrate
cp
;
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
cp
.
max_latency
=
cpu_to_le16
(
0
);
cp
.
min_remote_timeout
=
cpu_to_le16
(
0
);
cp
.
min_local_timeout
=
cpu_to_le16
(
0
);
hci_send_cmd
(
hdev
,
HCI_OP_SNIFF_SUBRATE
,
sizeof
(
cp
),
&
cp
);
}
if
(
!
test_and_set_bit
(
HCI_CONN_MODE_CHANGE_PEND
,
&
conn
->
pend
))
{
struct
hci_cp_sniff_mode
cp
;
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
cp
.
max_interval
=
cpu_to_le16
(
hdev
->
sniff_max_interval
);
cp
.
min_interval
=
cpu_to_le16
(
hdev
->
sniff_min_interval
);
cp
.
attempt
=
cpu_to_le16
(
4
);
cp
.
timeout
=
cpu_to_le16
(
1
);
hci_send_cmd
(
hdev
,
HCI_OP_SNIFF_MODE
,
sizeof
(
cp
),
&
cp
);
}
}
static
void
hci_conn_idle
(
unsigned
long
arg
)
static
void
hci_conn_idle
(
unsigned
long
arg
)
{
{
struct
hci_conn
*
conn
=
(
void
*
)
arg
;
struct
hci_conn
*
conn
=
(
void
*
)
arg
;
...
@@ -325,12 +362,8 @@ static void hci_conn_auto_accept(unsigned long arg)
...
@@ -325,12 +362,8 @@ static void hci_conn_auto_accept(unsigned long arg)
struct
hci_conn
*
conn
=
(
void
*
)
arg
;
struct
hci_conn
*
conn
=
(
void
*
)
arg
;
struct
hci_dev
*
hdev
=
conn
->
hdev
;
struct
hci_dev
*
hdev
=
conn
->
hdev
;
hci_dev_lock
(
hdev
);
hci_send_cmd
(
hdev
,
HCI_OP_USER_CONFIRM_REPLY
,
sizeof
(
conn
->
dst
),
hci_send_cmd
(
hdev
,
HCI_OP_USER_CONFIRM_REPLY
,
sizeof
(
conn
->
dst
),
&
conn
->
dst
);
&
conn
->
dst
);
hci_dev_unlock
(
hdev
);
}
}
struct
hci_conn
*
hci_conn_add
(
struct
hci_dev
*
hdev
,
int
type
,
bdaddr_t
*
dst
)
struct
hci_conn
*
hci_conn_add
(
struct
hci_dev
*
hdev
,
int
type
,
bdaddr_t
*
dst
)
...
@@ -374,9 +407,9 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
...
@@ -374,9 +407,9 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
skb_queue_head_init
(
&
conn
->
data_q
);
skb_queue_head_init
(
&
conn
->
data_q
);
hci_chan_hash_init
(
conn
)
;
INIT_LIST_HEAD
(
&
conn
->
chan_list
);
;
setup_timer
(
&
conn
->
disc_timer
,
hci_conn_timeout
,
(
unsigned
long
)
conn
);
INIT_DELAYED_WORK
(
&
conn
->
disc_work
,
hci_conn_timeout
);
setup_timer
(
&
conn
->
idle_timer
,
hci_conn_idle
,
(
unsigned
long
)
conn
);
setup_timer
(
&
conn
->
idle_timer
,
hci_conn_idle
,
(
unsigned
long
)
conn
);
setup_timer
(
&
conn
->
auto_accept_timer
,
hci_conn_auto_accept
,
setup_timer
(
&
conn
->
auto_accept_timer
,
hci_conn_auto_accept
,
(
unsigned
long
)
conn
);
(
unsigned
long
)
conn
);
...
@@ -385,8 +418,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
...
@@ -385,8 +418,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
hci_dev_hold
(
hdev
);
hci_dev_hold
(
hdev
);
tasklet_disable
(
&
hdev
->
tx_task
);
hci_conn_hash_add
(
hdev
,
conn
);
hci_conn_hash_add
(
hdev
,
conn
);
if
(
hdev
->
notify
)
if
(
hdev
->
notify
)
hdev
->
notify
(
hdev
,
HCI_NOTIFY_CONN_ADD
);
hdev
->
notify
(
hdev
,
HCI_NOTIFY_CONN_ADD
);
...
@@ -395,8 +426,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
...
@@ -395,8 +426,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
hci_conn_init_sysfs
(
conn
);
hci_conn_init_sysfs
(
conn
);
tasklet_enable
(
&
hdev
->
tx_task
);
return
conn
;
return
conn
;
}
}
...
@@ -408,7 +437,7 @@ int hci_conn_del(struct hci_conn *conn)
...
@@ -408,7 +437,7 @@ int hci_conn_del(struct hci_conn *conn)
del_timer
(
&
conn
->
idle_timer
);
del_timer
(
&
conn
->
idle_timer
);
del_timer
(
&
conn
->
disc_timer
);
cancel_delayed_work_sync
(
&
conn
->
disc_work
);
del_timer
(
&
conn
->
auto_accept_timer
);
del_timer
(
&
conn
->
auto_accept_timer
);
...
@@ -432,16 +461,13 @@ int hci_conn_del(struct hci_conn *conn)
...
@@ -432,16 +461,13 @@ int hci_conn_del(struct hci_conn *conn)
}
}
}
}
tasklet_disable
(
&
hdev
->
tx_task
);
hci_chan_
hash
_flush
(
conn
);
hci_chan_
list
_flush
(
conn
);
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
);
skb_queue_purge
(
&
conn
->
data_q
);
skb_queue_purge
(
&
conn
->
data_q
);
hci_conn_put_device
(
conn
);
hci_conn_put_device
(
conn
);
...
@@ -674,7 +700,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
...
@@ -674,7 +700,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
goto
encrypt
;
goto
encrypt
;
auth:
auth:
if
(
test_
and_set_
bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
pend
))
if
(
test_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
pend
))
return
0
;
return
0
;
if
(
!
hci_conn_auth
(
conn
,
sec_level
,
auth_type
))
if
(
!
hci_conn_auth
(
conn
,
sec_level
,
auth_type
))
...
@@ -767,57 +793,15 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
...
@@ -767,57 +793,15 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
jiffies
+
msecs_to_jiffies
(
hdev
->
idle_timeout
));
jiffies
+
msecs_to_jiffies
(
hdev
->
idle_timeout
));
}
}
/* Enter sniff mode */
void
hci_conn_enter_sniff_mode
(
struct
hci_conn
*
conn
)
{
struct
hci_dev
*
hdev
=
conn
->
hdev
;
BT_DBG
(
"conn %p mode %d"
,
conn
,
conn
->
mode
);
if
(
test_bit
(
HCI_RAW
,
&
hdev
->
flags
))
return
;
if
(
!
lmp_sniff_capable
(
hdev
)
||
!
lmp_sniff_capable
(
conn
))
return
;
if
(
conn
->
mode
!=
HCI_CM_ACTIVE
||
!
(
conn
->
link_policy
&
HCI_LP_SNIFF
))
return
;
if
(
lmp_sniffsubr_capable
(
hdev
)
&&
lmp_sniffsubr_capable
(
conn
))
{
struct
hci_cp_sniff_subrate
cp
;
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
cp
.
max_latency
=
cpu_to_le16
(
0
);
cp
.
min_remote_timeout
=
cpu_to_le16
(
0
);
cp
.
min_local_timeout
=
cpu_to_le16
(
0
);
hci_send_cmd
(
hdev
,
HCI_OP_SNIFF_SUBRATE
,
sizeof
(
cp
),
&
cp
);
}
if
(
!
test_and_set_bit
(
HCI_CONN_MODE_CHANGE_PEND
,
&
conn
->
pend
))
{
struct
hci_cp_sniff_mode
cp
;
cp
.
handle
=
cpu_to_le16
(
conn
->
handle
);
cp
.
max_interval
=
cpu_to_le16
(
hdev
->
sniff_max_interval
);
cp
.
min_interval
=
cpu_to_le16
(
hdev
->
sniff_min_interval
);
cp
.
attempt
=
cpu_to_le16
(
4
);
cp
.
timeout
=
cpu_to_le16
(
1
);
hci_send_cmd
(
hdev
,
HCI_OP_SNIFF_MODE
,
sizeof
(
cp
),
&
cp
);
}
}
/* Drop all connection on the device */
/* Drop all connection on the device */
void
hci_conn_hash_flush
(
struct
hci_dev
*
hdev
)
void
hci_conn_hash_flush
(
struct
hci_dev
*
hdev
)
{
{
struct
hci_conn_hash
*
h
=
&
hdev
->
conn_hash
;
struct
hci_conn_hash
*
h
=
&
hdev
->
conn_hash
;
struct
list_head
*
p
;
BT_DBG
(
"hdev %s"
,
hdev
->
name
);
p
=
h
->
list
.
next
;
while
(
p
!=
&
h
->
list
)
{
struct
hci_conn
*
c
;
struct
hci_conn
*
c
;
c
=
list_entry
(
p
,
struct
hci_conn
,
list
);
BT_DBG
(
"hdev %s"
,
hdev
->
name
);
p
=
p
->
next
;
list_for_each_entry_rcu
(
c
,
&
h
->
list
,
list
)
{
c
->
state
=
BT_CLOSED
;
c
->
state
=
BT_CLOSED
;
hci_proto_disconn_cfm
(
c
,
HCI_ERROR_LOCAL_HOST_TERM
);
hci_proto_disconn_cfm
(
c
,
HCI_ERROR_LOCAL_HOST_TERM
);
...
@@ -882,7 +866,7 @@ int hci_get_conn_list(void __user *arg)
...
@@ -882,7 +866,7 @@ int hci_get_conn_list(void __user *arg)
ci
=
cl
->
conn_info
;
ci
=
cl
->
conn_info
;
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
list_for_each_entry
(
c
,
&
hdev
->
conn_hash
.
list
,
list
)
{
list_for_each_entry
(
c
,
&
hdev
->
conn_hash
.
list
,
list
)
{
bacpy
(
&
(
ci
+
n
)
->
bdaddr
,
&
c
->
dst
);
bacpy
(
&
(
ci
+
n
)
->
bdaddr
,
&
c
->
dst
);
(
ci
+
n
)
->
handle
=
c
->
handle
;
(
ci
+
n
)
->
handle
=
c
->
handle
;
...
@@ -893,7 +877,7 @@ int hci_get_conn_list(void __user *arg)
...
@@ -893,7 +877,7 @@ int hci_get_conn_list(void __user *arg)
if
(
++
n
>=
req
.
conn_num
)
if
(
++
n
>=
req
.
conn_num
)
break
;
break
;
}
}
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
cl
->
dev_id
=
hdev
->
id
;
cl
->
dev_id
=
hdev
->
id
;
cl
->
conn_num
=
n
;
cl
->
conn_num
=
n
;
...
@@ -917,7 +901,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
...
@@ -917,7 +901,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
if
(
copy_from_user
(
&
req
,
arg
,
sizeof
(
req
)))
if
(
copy_from_user
(
&
req
,
arg
,
sizeof
(
req
)))
return
-
EFAULT
;
return
-
EFAULT
;
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
req
.
type
,
&
req
.
bdaddr
);
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
req
.
type
,
&
req
.
bdaddr
);
if
(
conn
)
{
if
(
conn
)
{
bacpy
(
&
ci
.
bdaddr
,
&
conn
->
dst
);
bacpy
(
&
ci
.
bdaddr
,
&
conn
->
dst
);
...
@@ -927,7 +911,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
...
@@ -927,7 +911,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
ci
.
state
=
conn
->
state
;
ci
.
state
=
conn
->
state
;
ci
.
link_mode
=
conn
->
link_mode
;
ci
.
link_mode
=
conn
->
link_mode
;
}
}
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
if
(
!
conn
)
if
(
!
conn
)
return
-
ENOENT
;
return
-
ENOENT
;
...
@@ -943,11 +927,11 @@ int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
...
@@ -943,11 +927,11 @@ int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
if
(
copy_from_user
(
&
req
,
arg
,
sizeof
(
req
)))
if
(
copy_from_user
(
&
req
,
arg
,
sizeof
(
req
)))
return
-
EFAULT
;
return
-
EFAULT
;
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
ACL_LINK
,
&
req
.
bdaddr
);
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
ACL_LINK
,
&
req
.
bdaddr
);
if
(
conn
)
if
(
conn
)
req
.
type
=
conn
->
auth_type
;
req
.
type
=
conn
->
auth_type
;
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
if
(
!
conn
)
if
(
!
conn
)
return
-
ENOENT
;
return
-
ENOENT
;
...
@@ -969,9 +953,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn)
...
@@ -969,9 +953,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn)
chan
->
conn
=
conn
;
chan
->
conn
=
conn
;
skb_queue_head_init
(
&
chan
->
data_q
);
skb_queue_head_init
(
&
chan
->
data_q
);
tasklet_disable
(
&
hdev
->
tx_task
);
list_add_rcu
(
&
chan
->
list
,
&
conn
->
chan_list
);
hci_chan_hash_add
(
conn
,
chan
);
tasklet_enable
(
&
hdev
->
tx_task
);
return
chan
;
return
chan
;
}
}
...
@@ -983,9 +965,9 @@ int hci_chan_del(struct hci_chan *chan)
...
@@ -983,9 +965,9 @@ int hci_chan_del(struct hci_chan *chan)
BT_DBG
(
"%s conn %p chan %p"
,
hdev
->
name
,
conn
,
chan
);
BT_DBG
(
"%s conn %p chan %p"
,
hdev
->
name
,
conn
,
chan
);
tasklet_disable
(
&
hdev
->
tx_task
);
list_del_rcu
(
&
chan
->
list
);
hci_chan_hash_del
(
conn
,
chan
);
tasklet_enable
(
&
hdev
->
tx_task
);
synchronize_rcu
(
);
skb_queue_purge
(
&
chan
->
data_q
);
skb_queue_purge
(
&
chan
->
data_q
);
kfree
(
chan
);
kfree
(
chan
);
...
@@ -993,13 +975,12 @@ int hci_chan_del(struct hci_chan *chan)
...
@@ -993,13 +975,12 @@ int hci_chan_del(struct hci_chan *chan)
return
0
;
return
0
;
}
}
void
hci_chan_
hash
_flush
(
struct
hci_conn
*
conn
)
void
hci_chan_
list
_flush
(
struct
hci_conn
*
conn
)
{
{
struct
hci_chan_hash
*
h
=
&
conn
->
chan_hash
;
struct
hci_chan
*
chan
;
struct
hci_chan
*
chan
,
*
tmp
;
BT_DBG
(
"conn %p"
,
conn
);
BT_DBG
(
"conn %p"
,
conn
);
list_for_each_entry_
safe
(
chan
,
tmp
,
&
h
->
list
,
list
)
list_for_each_entry_
rcu
(
chan
,
&
conn
->
chan_
list
,
list
)
hci_chan_del
(
chan
);
hci_chan_del
(
chan
);
}
}
net/bluetooth/hci_core.c
View file @
9662cbc7
/*
/*
BlueZ - Bluetooth protocol stack for Linux
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated
Copyright (C) 2000-2001 Qualcomm Incorporated
Copyright (C) 2011 ProFUSION Embedded Systems
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
...
@@ -56,11 +57,11 @@
...
@@ -56,11 +57,11 @@
int
enable_hs
;
int
enable_hs
;
static
void
hci_
cmd_task
(
unsigned
long
arg
);
static
void
hci_
rx_work
(
struct
work_struct
*
work
);
static
void
hci_
rx_task
(
unsigned
long
arg
);
static
void
hci_
cmd_work
(
struct
work_struct
*
work
);
static
void
hci_tx_
task
(
unsigned
long
arg
);
static
void
hci_tx_
work
(
struct
work_struct
*
work
);
static
DEFINE_
RWLOCK
(
hci_task_lock
);
static
DEFINE_
MUTEX
(
hci_task_lock
);
/* HCI device list */
/* HCI device list */
LIST_HEAD
(
hci_dev_list
);
LIST_HEAD
(
hci_dev_list
);
...
@@ -209,7 +210,7 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
...
@@ -209,7 +210,7 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
skb
->
dev
=
(
void
*
)
hdev
;
skb
->
dev
=
(
void
*
)
hdev
;
skb_queue_tail
(
&
hdev
->
cmd_q
,
skb
);
skb_queue_tail
(
&
hdev
->
cmd_q
,
skb
);
tasklet_schedule
(
&
hdev
->
cmd_tas
k
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
cmd_wor
k
);
}
}
skb_queue_purge
(
&
hdev
->
driver_init
);
skb_queue_purge
(
&
hdev
->
driver_init
);
...
@@ -433,14 +434,14 @@ int hci_inquiry(void __user *arg)
...
@@ -433,14 +434,14 @@ int hci_inquiry(void __user *arg)
if
(
!
hdev
)
if
(
!
hdev
)
return
-
ENODEV
;
return
-
ENODEV
;
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
if
(
inquiry_cache_age
(
hdev
)
>
INQUIRY_CACHE_AGE_MAX
||
if
(
inquiry_cache_age
(
hdev
)
>
INQUIRY_CACHE_AGE_MAX
||
inquiry_cache_empty
(
hdev
)
||
inquiry_cache_empty
(
hdev
)
||
ir
.
flags
&
IREQ_CACHE_FLUSH
)
{
ir
.
flags
&
IREQ_CACHE_FLUSH
)
{
inquiry_cache_flush
(
hdev
);
inquiry_cache_flush
(
hdev
);
do_inquiry
=
1
;
do_inquiry
=
1
;
}
}
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
timeo
=
ir
.
length
*
msecs_to_jiffies
(
2000
);
timeo
=
ir
.
length
*
msecs_to_jiffies
(
2000
);
...
@@ -462,9 +463,9 @@ int hci_inquiry(void __user *arg)
...
@@ -462,9 +463,9 @@ int hci_inquiry(void __user *arg)
goto
done
;
goto
done
;
}
}
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
ir
.
num_rsp
=
inquiry_cache_dump
(
hdev
,
max_rsp
,
buf
);
ir
.
num_rsp
=
inquiry_cache_dump
(
hdev
,
max_rsp
,
buf
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
BT_DBG
(
"num_rsp %d"
,
ir
.
num_rsp
);
BT_DBG
(
"num_rsp %d"
,
ir
.
num_rsp
);
...
@@ -541,15 +542,15 @@ int hci_dev_open(__u16 dev)
...
@@ -541,15 +542,15 @@ int hci_dev_open(__u16 dev)
set_bit
(
HCI_UP
,
&
hdev
->
flags
);
set_bit
(
HCI_UP
,
&
hdev
->
flags
);
hci_notify
(
hdev
,
HCI_DEV_UP
);
hci_notify
(
hdev
,
HCI_DEV_UP
);
if
(
!
test_bit
(
HCI_SETUP
,
&
hdev
->
flags
))
{
if
(
!
test_bit
(
HCI_SETUP
,
&
hdev
->
flags
))
{
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
mgmt_powered
(
hdev
,
1
);
mgmt_powered
(
hdev
,
1
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
}
}
}
else
{
}
else
{
/* Init failed, cleanup */
/* Init failed, cleanup */
tasklet_kill
(
&
hdev
->
rx_tas
k
);
flush_work
(
&
hdev
->
tx_wor
k
);
tasklet_kill
(
&
hdev
->
tx_tas
k
);
flush_work
(
&
hdev
->
cmd_wor
k
);
tasklet_kill
(
&
hdev
->
cmd_tas
k
);
flush_work
(
&
hdev
->
rx_wor
k
);
skb_queue_purge
(
&
hdev
->
cmd_q
);
skb_queue_purge
(
&
hdev
->
cmd_q
);
skb_queue_purge
(
&
hdev
->
rx_q
);
skb_queue_purge
(
&
hdev
->
rx_q
);
...
@@ -585,9 +586,9 @@ static int hci_dev_do_close(struct hci_dev *hdev)
...
@@ -585,9 +586,9 @@ static int hci_dev_do_close(struct hci_dev *hdev)
return
0
;
return
0
;
}
}
/*
Kill RX and TX tas
ks */
/*
Flush RX and TX wor
ks */
tasklet_kill
(
&
hdev
->
rx_tas
k
);
flush_work
(
&
hdev
->
tx_wor
k
);
tasklet_kill
(
&
hdev
->
tx_tas
k
);
flush_work
(
&
hdev
->
rx_wor
k
);
if
(
hdev
->
discov_timeout
>
0
)
{
if
(
hdev
->
discov_timeout
>
0
)
{
cancel_delayed_work
(
&
hdev
->
discov_off
);
cancel_delayed_work
(
&
hdev
->
discov_off
);
...
@@ -597,10 +598,13 @@ static int hci_dev_do_close(struct hci_dev *hdev)
...
@@ -597,10 +598,13 @@ static int hci_dev_do_close(struct hci_dev *hdev)
if
(
test_and_clear_bit
(
HCI_AUTO_OFF
,
&
hdev
->
flags
))
if
(
test_and_clear_bit
(
HCI_AUTO_OFF
,
&
hdev
->
flags
))
cancel_delayed_work
(
&
hdev
->
power_off
);
cancel_delayed_work
(
&
hdev
->
power_off
);
hci_dev_lock_bh
(
hdev
);
if
(
test_and_clear_bit
(
HCI_SERVICE_CACHE
,
&
hdev
->
flags
))
cancel_delayed_work
(
&
hdev
->
service_cache
);
hci_dev_lock
(
hdev
);
inquiry_cache_flush
(
hdev
);
inquiry_cache_flush
(
hdev
);
hci_conn_hash_flush
(
hdev
);
hci_conn_hash_flush
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_notify
(
hdev
,
HCI_DEV_DOWN
);
hci_notify
(
hdev
,
HCI_DEV_DOWN
);
...
@@ -617,8 +621,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
...
@@ -617,8 +621,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
clear_bit
(
HCI_INIT
,
&
hdev
->
flags
);
clear_bit
(
HCI_INIT
,
&
hdev
->
flags
);
}
}
/*
Kill cmd tas
k */
/*
flush cmd wor
k */
tasklet_kill
(
&
hdev
->
cmd_tas
k
);
flush_work
(
&
hdev
->
cmd_wor
k
);
/* Drop queues */
/* Drop queues */
skb_queue_purge
(
&
hdev
->
rx_q
);
skb_queue_purge
(
&
hdev
->
rx_q
);
...
@@ -636,9 +640,9 @@ static int hci_dev_do_close(struct hci_dev *hdev)
...
@@ -636,9 +640,9 @@ static int hci_dev_do_close(struct hci_dev *hdev)
* and no tasks are scheduled. */
* and no tasks are scheduled. */
hdev
->
close
(
hdev
);
hdev
->
close
(
hdev
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
mgmt_powered
(
hdev
,
0
);
mgmt_powered
(
hdev
,
0
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
/* Clear flags */
/* Clear flags */
hdev
->
flags
=
0
;
hdev
->
flags
=
0
;
...
@@ -672,7 +676,6 @@ int hci_dev_reset(__u16 dev)
...
@@ -672,7 +676,6 @@ int hci_dev_reset(__u16 dev)
return
-
ENODEV
;
return
-
ENODEV
;
hci_req_lock
(
hdev
);
hci_req_lock
(
hdev
);
tasklet_disable
(
&
hdev
->
tx_task
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
goto
done
;
goto
done
;
...
@@ -681,10 +684,10 @@ int hci_dev_reset(__u16 dev)
...
@@ -681,10 +684,10 @@ int hci_dev_reset(__u16 dev)
skb_queue_purge
(
&
hdev
->
rx_q
);
skb_queue_purge
(
&
hdev
->
rx_q
);
skb_queue_purge
(
&
hdev
->
cmd_q
);
skb_queue_purge
(
&
hdev
->
cmd_q
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
inquiry_cache_flush
(
hdev
);
inquiry_cache_flush
(
hdev
);
hci_conn_hash_flush
(
hdev
);
hci_conn_hash_flush
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
if
(
hdev
->
flush
)
if
(
hdev
->
flush
)
hdev
->
flush
(
hdev
);
hdev
->
flush
(
hdev
);
...
@@ -697,7 +700,6 @@ int hci_dev_reset(__u16 dev)
...
@@ -697,7 +700,6 @@ int hci_dev_reset(__u16 dev)
msecs_to_jiffies
(
HCI_INIT_TIMEOUT
));
msecs_to_jiffies
(
HCI_INIT_TIMEOUT
));
done:
done:
tasklet_enable
(
&
hdev
->
tx_task
);
hci_req_unlock
(
hdev
);
hci_req_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
ret
;
return
ret
;
...
@@ -939,7 +941,7 @@ static void hci_power_on(struct work_struct *work)
...
@@ -939,7 +941,7 @@ static void hci_power_on(struct work_struct *work)
return
;
return
;
if
(
test_bit
(
HCI_AUTO_OFF
,
&
hdev
->
flags
))
if
(
test_bit
(
HCI_AUTO_OFF
,
&
hdev
->
flags
))
queue_delayed_work
(
hdev
->
workqueue
,
&
hdev
->
power_off
,
schedule_delayed_work
(
&
hdev
->
power_off
,
msecs_to_jiffies
(
AUTO_OFF_TIMEOUT
));
msecs_to_jiffies
(
AUTO_OFF_TIMEOUT
));
if
(
test_and_clear_bit
(
HCI_SETUP
,
&
hdev
->
flags
))
if
(
test_and_clear_bit
(
HCI_SETUP
,
&
hdev
->
flags
))
...
@@ -967,13 +969,13 @@ static void hci_discov_off(struct work_struct *work)
...
@@ -967,13 +969,13 @@ static void hci_discov_off(struct work_struct *work)
BT_DBG
(
"%s"
,
hdev
->
name
);
BT_DBG
(
"%s"
,
hdev
->
name
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
hci_send_cmd
(
hdev
,
HCI_OP_WRITE_SCAN_ENABLE
,
sizeof
(
scan
),
&
scan
);
hci_send_cmd
(
hdev
,
HCI_OP_WRITE_SCAN_ENABLE
,
sizeof
(
scan
),
&
scan
);
hdev
->
discov_timeout
=
0
;
hdev
->
discov_timeout
=
0
;
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
}
}
int
hci_uuids_clear
(
struct
hci_dev
*
hdev
)
int
hci_uuids_clear
(
struct
hci_dev
*
hdev
)
...
@@ -1207,7 +1209,7 @@ static void hci_cmd_timer(unsigned long arg)
...
@@ -1207,7 +1209,7 @@ static void hci_cmd_timer(unsigned long arg)
BT_ERR
(
"%s command tx timeout"
,
hdev
->
name
);
BT_ERR
(
"%s command tx timeout"
,
hdev
->
name
);
atomic_set
(
&
hdev
->
cmd_cnt
,
1
);
atomic_set
(
&
hdev
->
cmd_cnt
,
1
);
tasklet_schedule
(
&
hdev
->
cmd_tas
k
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
cmd_wor
k
);
}
}
struct
oob_data
*
hci_find_remote_oob_data
(
struct
hci_dev
*
hdev
,
struct
oob_data
*
hci_find_remote_oob_data
(
struct
hci_dev
*
hdev
,
...
@@ -1340,9 +1342,10 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
...
@@ -1340,9 +1342,10 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
return
mgmt_device_unblocked
(
hdev
,
bdaddr
);
return
mgmt_device_unblocked
(
hdev
,
bdaddr
);
}
}
static
void
hci_clear_adv_cache
(
unsigned
long
arg
)
static
void
hci_clear_adv_cache
(
struct
work_struct
*
work
)
{
{
struct
hci_dev
*
hdev
=
(
void
*
)
arg
;
struct
hci_dev
*
hdev
=
container_of
(
work
,
struct
hci_dev
,
adv_work
.
work
);
hci_dev_lock
(
hdev
);
hci_dev_lock
(
hdev
);
...
@@ -1443,7 +1446,7 @@ int hci_register_dev(struct hci_dev *hdev)
...
@@ -1443,7 +1446,7 @@ int hci_register_dev(struct hci_dev *hdev)
list_add_tail
(
&
hdev
->
list
,
head
);
list_add_tail
(
&
hdev
->
list
,
head
);
atomic_set
(
&
hdev
->
refcnt
,
1
);
atomic_set
(
&
hdev
->
refcnt
,
1
);
spin_lock
_init
(
&
hdev
->
lock
);
mutex
_init
(
&
hdev
->
lock
);
hdev
->
flags
=
0
;
hdev
->
flags
=
0
;
hdev
->
dev_flags
=
0
;
hdev
->
dev_flags
=
0
;
...
@@ -1456,9 +1459,10 @@ int hci_register_dev(struct hci_dev *hdev)
...
@@ -1456,9 +1459,10 @@ int hci_register_dev(struct hci_dev *hdev)
hdev
->
sniff_max_interval
=
800
;
hdev
->
sniff_max_interval
=
800
;
hdev
->
sniff_min_interval
=
80
;
hdev
->
sniff_min_interval
=
80
;
tasklet_init
(
&
hdev
->
cmd_task
,
hci_cmd_task
,
(
unsigned
long
)
hdev
);
INIT_WORK
(
&
hdev
->
rx_work
,
hci_rx_work
);
tasklet_init
(
&
hdev
->
rx_task
,
hci_rx_task
,
(
unsigned
long
)
hdev
);
INIT_WORK
(
&
hdev
->
cmd_work
,
hci_cmd_work
);
tasklet_init
(
&
hdev
->
tx_task
,
hci_tx_task
,
(
unsigned
long
)
hdev
);
INIT_WORK
(
&
hdev
->
tx_work
,
hci_tx_work
);
skb_queue_head_init
(
&
hdev
->
rx_q
);
skb_queue_head_init
(
&
hdev
->
rx_q
);
skb_queue_head_init
(
&
hdev
->
cmd_q
);
skb_queue_head_init
(
&
hdev
->
cmd_q
);
...
@@ -1487,9 +1491,8 @@ int hci_register_dev(struct hci_dev *hdev)
...
@@ -1487,9 +1491,8 @@ int hci_register_dev(struct hci_dev *hdev)
INIT_LIST_HEAD
(
&
hdev
->
remote_oob_data
);
INIT_LIST_HEAD
(
&
hdev
->
remote_oob_data
);
INIT_LIST_HEAD
(
&
hdev
->
adv_entries
);
INIT_LIST_HEAD
(
&
hdev
->
adv_entries
);
setup_timer
(
&
hdev
->
adv_timer
,
hci_clear_adv_cache
,
(
unsigned
long
)
hdev
);
INIT_DELAYED_WORK
(
&
hdev
->
adv_work
,
hci_clear_adv_cache
);
INIT_WORK
(
&
hdev
->
power_on
,
hci_power_on
);
INIT_WORK
(
&
hdev
->
power_on
,
hci_power_on
);
INIT_DELAYED_WORK
(
&
hdev
->
power_off
,
hci_power_off
);
INIT_DELAYED_WORK
(
&
hdev
->
power_off
,
hci_power_off
);
...
@@ -1501,7 +1504,8 @@ int hci_register_dev(struct hci_dev *hdev)
...
@@ -1501,7 +1504,8 @@ int hci_register_dev(struct hci_dev *hdev)
write_unlock_bh
(
&
hci_dev_list_lock
);
write_unlock_bh
(
&
hci_dev_list_lock
);
hdev
->
workqueue
=
create_singlethread_workqueue
(
hdev
->
name
);
hdev
->
workqueue
=
alloc_workqueue
(
hdev
->
name
,
WQ_HIGHPRI
|
WQ_UNBOUND
|
WQ_MEM_RECLAIM
,
1
);
if
(
!
hdev
->
workqueue
)
{
if
(
!
hdev
->
workqueue
)
{
error
=
-
ENOMEM
;
error
=
-
ENOMEM
;
goto
err
;
goto
err
;
...
@@ -1522,7 +1526,7 @@ int hci_register_dev(struct hci_dev *hdev)
...
@@ -1522,7 +1526,7 @@ int hci_register_dev(struct hci_dev *hdev)
set_bit
(
HCI_AUTO_OFF
,
&
hdev
->
flags
);
set_bit
(
HCI_AUTO_OFF
,
&
hdev
->
flags
);
set_bit
(
HCI_SETUP
,
&
hdev
->
flags
);
set_bit
(
HCI_SETUP
,
&
hdev
->
flags
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
power_on
);
schedule_work
(
&
hdev
->
power_on
);
hci_notify
(
hdev
,
HCI_DEV_REG
);
hci_notify
(
hdev
,
HCI_DEV_REG
);
...
@@ -1557,9 +1561,9 @@ void hci_unregister_dev(struct hci_dev *hdev)
...
@@ -1557,9 +1561,9 @@ void hci_unregister_dev(struct hci_dev *hdev)
if
(
!
test_bit
(
HCI_INIT
,
&
hdev
->
flags
)
&&
if
(
!
test_bit
(
HCI_INIT
,
&
hdev
->
flags
)
&&
!
test_bit
(
HCI_SETUP
,
&
hdev
->
flags
))
{
!
test_bit
(
HCI_SETUP
,
&
hdev
->
flags
))
{
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
mgmt_index_removed
(
hdev
);
mgmt_index_removed
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
}
}
/* mgmt_index_removed should take care of emptying the
/* mgmt_index_removed should take care of emptying the
...
@@ -1575,17 +1579,17 @@ void hci_unregister_dev(struct hci_dev *hdev)
...
@@ -1575,17 +1579,17 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_del_sysfs
(
hdev
);
hci_del_sysfs
(
hdev
);
del_timer
(
&
hdev
->
adv_timer
);
cancel_delayed_work_sync
(
&
hdev
->
adv_work
);
destroy_workqueue
(
hdev
->
workqueue
);
destroy_workqueue
(
hdev
->
workqueue
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
hci_blacklist_clear
(
hdev
);
hci_blacklist_clear
(
hdev
);
hci_uuids_clear
(
hdev
);
hci_uuids_clear
(
hdev
);
hci_link_keys_clear
(
hdev
);
hci_link_keys_clear
(
hdev
);
hci_remote_oob_data_clear
(
hdev
);
hci_remote_oob_data_clear
(
hdev
);
hci_adv_entries_clear
(
hdev
);
hci_adv_entries_clear
(
hdev
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
__hci_dev_put
(
hdev
);
__hci_dev_put
(
hdev
);
}
}
...
@@ -1623,9 +1627,8 @@ int hci_recv_frame(struct sk_buff *skb)
...
@@ -1623,9 +1627,8 @@ int hci_recv_frame(struct sk_buff *skb)
/* Time stamp */
/* Time stamp */
__net_timestamp
(
skb
);
__net_timestamp
(
skb
);
/* Queue frame for rx task */
skb_queue_tail
(
&
hdev
->
rx_q
,
skb
);
skb_queue_tail
(
&
hdev
->
rx_q
,
skb
);
tasklet_schedule
(
&
hdev
->
rx_tas
k
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
rx_wor
k
);
return
0
;
return
0
;
}
}
...
@@ -1808,14 +1811,14 @@ int hci_register_proto(struct hci_proto *hp)
...
@@ -1808,14 +1811,14 @@ int hci_register_proto(struct hci_proto *hp)
if
(
hp
->
id
>=
HCI_MAX_PROTO
)
if
(
hp
->
id
>=
HCI_MAX_PROTO
)
return
-
EINVAL
;
return
-
EINVAL
;
write_lock_bh
(
&
hci_task_lock
);
mutex_lock
(
&
hci_task_lock
);
if
(
!
hci_proto
[
hp
->
id
])
if
(
!
hci_proto
[
hp
->
id
])
hci_proto
[
hp
->
id
]
=
hp
;
hci_proto
[
hp
->
id
]
=
hp
;
else
else
err
=
-
EEXIST
;
err
=
-
EEXIST
;
write_unlock_bh
(
&
hci_task_lock
);
mutex_unlock
(
&
hci_task_lock
);
return
err
;
return
err
;
}
}
...
@@ -1830,14 +1833,14 @@ int hci_unregister_proto(struct hci_proto *hp)
...
@@ -1830,14 +1833,14 @@ int hci_unregister_proto(struct hci_proto *hp)
if
(
hp
->
id
>=
HCI_MAX_PROTO
)
if
(
hp
->
id
>=
HCI_MAX_PROTO
)
return
-
EINVAL
;
return
-
EINVAL
;
write_lock_bh
(
&
hci_task_lock
);
mutex_lock
(
&
hci_task_lock
);
if
(
hci_proto
[
hp
->
id
])
if
(
hci_proto
[
hp
->
id
])
hci_proto
[
hp
->
id
]
=
NULL
;
hci_proto
[
hp
->
id
]
=
NULL
;
else
else
err
=
-
ENOENT
;
err
=
-
ENOENT
;
write_unlock_bh
(
&
hci_task_lock
);
mutex_unlock
(
&
hci_task_lock
);
return
err
;
return
err
;
}
}
...
@@ -1922,7 +1925,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
...
@@ -1922,7 +1925,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
hdev
->
init_last_cmd
=
opcode
;
hdev
->
init_last_cmd
=
opcode
;
skb_queue_tail
(
&
hdev
->
cmd_q
,
skb
);
skb_queue_tail
(
&
hdev
->
cmd_q
,
skb
);
tasklet_schedule
(
&
hdev
->
cmd_tas
k
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
cmd_wor
k
);
return
0
;
return
0
;
}
}
...
@@ -2012,7 +2015,7 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
...
@@ -2012,7 +2015,7 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
hci_queue_acl
(
conn
,
&
chan
->
data_q
,
skb
,
flags
);
hci_queue_acl
(
conn
,
&
chan
->
data_q
,
skb
,
flags
);
tasklet_schedule
(
&
hdev
->
tx_tas
k
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
tx_wor
k
);
}
}
EXPORT_SYMBOL
(
hci_send_acl
);
EXPORT_SYMBOL
(
hci_send_acl
);
...
@@ -2035,7 +2038,7 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
...
@@ -2035,7 +2038,7 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
bt_cb
(
skb
)
->
pkt_type
=
HCI_SCODATA_PKT
;
bt_cb
(
skb
)
->
pkt_type
=
HCI_SCODATA_PKT
;
skb_queue_tail
(
&
conn
->
data_q
,
skb
);
skb_queue_tail
(
&
conn
->
data_q
,
skb
);
tasklet_schedule
(
&
hdev
->
tx_tas
k
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
tx_wor
k
);
}
}
EXPORT_SYMBOL
(
hci_send_sco
);
EXPORT_SYMBOL
(
hci_send_sco
);
...
@@ -2050,7 +2053,10 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
...
@@ -2050,7 +2053,10 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
/* We don't have to lock device here. Connections are always
/* We don't have to lock device here. Connections are always
* added and removed with TX task disabled. */
* added and removed with TX task disabled. */
list_for_each_entry
(
c
,
&
h
->
list
,
list
)
{
rcu_read_lock
();
list_for_each_entry_rcu
(
c
,
&
h
->
list
,
list
)
{
if
(
c
->
type
!=
type
||
skb_queue_empty
(
&
c
->
data_q
))
if
(
c
->
type
!=
type
||
skb_queue_empty
(
&
c
->
data_q
))
continue
;
continue
;
...
@@ -2068,6 +2074,8 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
...
@@ -2068,6 +2074,8 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
break
;
break
;
}
}
rcu_read_unlock
();
if
(
conn
)
{
if
(
conn
)
{
int
cnt
,
q
;
int
cnt
,
q
;
...
@@ -2103,14 +2111,18 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
...
@@ -2103,14 +2111,18 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
BT_ERR
(
"%s link tx timeout"
,
hdev
->
name
);
BT_ERR
(
"%s link tx timeout"
,
hdev
->
name
);
rcu_read_lock
();
/* Kill stalled connections */
/* Kill stalled connections */
list_for_each_entry
(
c
,
&
h
->
list
,
list
)
{
list_for_each_entry
_rcu
(
c
,
&
h
->
list
,
list
)
{
if
(
c
->
type
==
type
&&
c
->
sent
)
{
if
(
c
->
type
==
type
&&
c
->
sent
)
{
BT_ERR
(
"%s killing stalled connection %s"
,
BT_ERR
(
"%s killing stalled connection %s"
,
hdev
->
name
,
batostr
(
&
c
->
dst
));
hdev
->
name
,
batostr
(
&
c
->
dst
));
hci_acl_disconn
(
c
,
0x13
);
hci_acl_disconn
(
c
,
0x13
);
}
}
}
}
rcu_read_unlock
();
}
}
static
inline
struct
hci_chan
*
hci_chan_sent
(
struct
hci_dev
*
hdev
,
__u8
type
,
static
inline
struct
hci_chan
*
hci_chan_sent
(
struct
hci_dev
*
hdev
,
__u8
type
,
...
@@ -2124,8 +2136,9 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
...
@@ -2124,8 +2136,9 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
BT_DBG
(
"%s"
,
hdev
->
name
);
BT_DBG
(
"%s"
,
hdev
->
name
);
list_for_each_entry
(
conn
,
&
h
->
list
,
list
)
{
rcu_read_lock
();
struct
hci_chan_hash
*
ch
;
list_for_each_entry_rcu
(
conn
,
&
h
->
list
,
list
)
{
struct
hci_chan
*
tmp
;
struct
hci_chan
*
tmp
;
if
(
conn
->
type
!=
type
)
if
(
conn
->
type
!=
type
)
...
@@ -2136,9 +2149,7 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
...
@@ -2136,9 +2149,7 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
conn_num
++
;
conn_num
++
;
ch
=
&
conn
->
chan_hash
;
list_for_each_entry_rcu
(
tmp
,
&
conn
->
chan_list
,
list
)
{
list_for_each_entry
(
tmp
,
&
ch
->
list
,
list
)
{
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
if
(
skb_queue_empty
(
&
tmp
->
data_q
))
if
(
skb_queue_empty
(
&
tmp
->
data_q
))
...
@@ -2166,6 +2177,8 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
...
@@ -2166,6 +2177,8 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
break
;
break
;
}
}
rcu_read_unlock
();
if
(
!
chan
)
if
(
!
chan
)
return
NULL
;
return
NULL
;
...
@@ -2199,8 +2212,9 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
...
@@ -2199,8 +2212,9 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
BT_DBG
(
"%s"
,
hdev
->
name
);
BT_DBG
(
"%s"
,
hdev
->
name
);
list_for_each_entry
(
conn
,
&
h
->
list
,
list
)
{
rcu_read_lock
();
struct
hci_chan_hash
*
ch
;
list_for_each_entry_rcu
(
conn
,
&
h
->
list
,
list
)
{
struct
hci_chan
*
chan
;
struct
hci_chan
*
chan
;
if
(
conn
->
type
!=
type
)
if
(
conn
->
type
!=
type
)
...
@@ -2211,8 +2225,7 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
...
@@ -2211,8 +2225,7 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
num
++
;
num
++
;
ch
=
&
conn
->
chan_hash
;
list_for_each_entry_rcu
(
chan
,
&
conn
->
chan_list
,
list
)
{
list_for_each_entry
(
chan
,
&
ch
->
list
,
list
)
{
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
if
(
chan
->
sent
)
{
if
(
chan
->
sent
)
{
...
@@ -2236,6 +2249,9 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
...
@@ -2236,6 +2249,9 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
if
(
hci_conn_num
(
hdev
,
type
)
==
num
)
if
(
hci_conn_num
(
hdev
,
type
)
==
num
)
break
;
break
;
}
}
rcu_read_unlock
();
}
}
static
inline
void
hci_sched_acl
(
struct
hci_dev
*
hdev
)
static
inline
void
hci_sched_acl
(
struct
hci_dev
*
hdev
)
...
@@ -2386,12 +2402,12 @@ static inline void hci_sched_le(struct hci_dev *hdev)
...
@@ -2386,12 +2402,12 @@ static inline void hci_sched_le(struct hci_dev *hdev)
hci_prio_recalculate
(
hdev
,
LE_LINK
);
hci_prio_recalculate
(
hdev
,
LE_LINK
);
}
}
static
void
hci_tx_
task
(
unsigned
long
arg
)
static
void
hci_tx_
work
(
struct
work_struct
*
work
)
{
{
struct
hci_dev
*
hdev
=
(
struct
hci_dev
*
)
arg
;
struct
hci_dev
*
hdev
=
container_of
(
work
,
struct
hci_dev
,
tx_work
)
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
read
_lock
(
&
hci_task_lock
);
mutex
_lock
(
&
hci_task_lock
);
BT_DBG
(
"%s acl %d sco %d le %d"
,
hdev
->
name
,
hdev
->
acl_cnt
,
BT_DBG
(
"%s acl %d sco %d le %d"
,
hdev
->
name
,
hdev
->
acl_cnt
,
hdev
->
sco_cnt
,
hdev
->
le_cnt
);
hdev
->
sco_cnt
,
hdev
->
le_cnt
);
...
@@ -2410,7 +2426,7 @@ static void hci_tx_task(unsigned long arg)
...
@@ -2410,7 +2426,7 @@ static void hci_tx_task(unsigned long arg)
while
((
skb
=
skb_dequeue
(
&
hdev
->
raw_q
)))
while
((
skb
=
skb_dequeue
(
&
hdev
->
raw_q
)))
hci_send_frame
(
skb
);
hci_send_frame
(
skb
);
read
_unlock
(
&
hci_task_lock
);
mutex
_unlock
(
&
hci_task_lock
);
}
}
/* ----- HCI RX task (incoming data processing) ----- */
/* ----- HCI RX task (incoming data processing) ----- */
...
@@ -2439,7 +2455,7 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -2439,7 +2455,7 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
if
(
conn
)
{
if
(
conn
)
{
register
struct
hci_proto
*
hp
;
register
struct
hci_proto
*
hp
;
hci_conn_enter_active_mode
(
conn
,
bt_cb
(
skb
)
->
force_active
);
hci_conn_enter_active_mode
(
conn
,
BT_POWER_FORCE_ACTIVE_OFF
);
/* Send to upper protocol */
/* Send to upper protocol */
hp
=
hci_proto
[
HCI_PROTO_L2CAP
];
hp
=
hci_proto
[
HCI_PROTO_L2CAP
];
...
@@ -2491,14 +2507,14 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -2491,14 +2507,14 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
kfree_skb
(
skb
);
kfree_skb
(
skb
);
}
}
static
void
hci_rx_
task
(
unsigned
long
arg
)
static
void
hci_rx_
work
(
struct
work_struct
*
work
)
{
{
struct
hci_dev
*
hdev
=
(
struct
hci_dev
*
)
arg
;
struct
hci_dev
*
hdev
=
container_of
(
work
,
struct
hci_dev
,
rx_work
)
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
BT_DBG
(
"%s"
,
hdev
->
name
);
BT_DBG
(
"%s"
,
hdev
->
name
);
read
_lock
(
&
hci_task_lock
);
mutex
_lock
(
&
hci_task_lock
);
while
((
skb
=
skb_dequeue
(
&
hdev
->
rx_q
)))
{
while
((
skb
=
skb_dequeue
(
&
hdev
->
rx_q
)))
{
if
(
atomic_read
(
&
hdev
->
promisc
))
{
if
(
atomic_read
(
&
hdev
->
promisc
))
{
...
@@ -2524,6 +2540,7 @@ static void hci_rx_task(unsigned long arg)
...
@@ -2524,6 +2540,7 @@ static void hci_rx_task(unsigned long arg)
/* Process frame */
/* Process frame */
switch
(
bt_cb
(
skb
)
->
pkt_type
)
{
switch
(
bt_cb
(
skb
)
->
pkt_type
)
{
case
HCI_EVENT_PKT
:
case
HCI_EVENT_PKT
:
BT_DBG
(
"%s Event packet"
,
hdev
->
name
);
hci_event_packet
(
hdev
,
skb
);
hci_event_packet
(
hdev
,
skb
);
break
;
break
;
...
@@ -2543,12 +2560,12 @@ static void hci_rx_task(unsigned long arg)
...
@@ -2543,12 +2560,12 @@ static void hci_rx_task(unsigned long arg)
}
}
}
}
read
_unlock
(
&
hci_task_lock
);
mutex
_unlock
(
&
hci_task_lock
);
}
}
static
void
hci_cmd_
task
(
unsigned
long
arg
)
static
void
hci_cmd_
work
(
struct
work_struct
*
work
)
{
{
struct
hci_dev
*
hdev
=
(
struct
hci_dev
*
)
arg
;
struct
hci_dev
*
hdev
=
container_of
(
work
,
struct
hci_dev
,
cmd_work
)
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
BT_DBG
(
"%s cmd %d"
,
hdev
->
name
,
atomic_read
(
&
hdev
->
cmd_cnt
));
BT_DBG
(
"%s cmd %d"
,
hdev
->
name
,
atomic_read
(
&
hdev
->
cmd_cnt
));
...
@@ -2572,7 +2589,7 @@ static void hci_cmd_task(unsigned long arg)
...
@@ -2572,7 +2589,7 @@ static void hci_cmd_task(unsigned long arg)
jiffies
+
msecs_to_jiffies
(
HCI_CMD_TIMEOUT
));
jiffies
+
msecs_to_jiffies
(
HCI_CMD_TIMEOUT
));
}
else
{
}
else
{
skb_queue_head
(
&
hdev
->
cmd_q
,
skb
);
skb_queue_head
(
&
hdev
->
cmd_q
,
skb
);
tasklet_schedule
(
&
hdev
->
cmd_tas
k
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
cmd_wor
k
);
}
}
}
}
}
}
...
...
net/bluetooth/hci_event.c
View file @
9662cbc7
...
@@ -378,11 +378,8 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -378,11 +378,8 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG
(
"%s voice setting 0x%04x"
,
hdev
->
name
,
setting
);
BT_DBG
(
"%s voice setting 0x%04x"
,
hdev
->
name
,
setting
);
if
(
hdev
->
notify
)
{
if
(
hdev
->
notify
)
tasklet_disable
(
&
hdev
->
tx_task
);
hdev
->
notify
(
hdev
,
HCI_NOTIFY_VOICE_SETTING
);
hdev
->
notify
(
hdev
,
HCI_NOTIFY_VOICE_SETTING
);
tasklet_enable
(
&
hdev
->
tx_task
);
}
}
}
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
)
...
@@ -409,11 +406,8 @@ static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb
...
@@ -409,11 +406,8 @@ static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb
BT_DBG
(
"%s voice setting 0x%04x"
,
hdev
->
name
,
setting
);
BT_DBG
(
"%s voice setting 0x%04x"
,
hdev
->
name
,
setting
);
if
(
hdev
->
notify
)
{
if
(
hdev
->
notify
)
tasklet_disable
(
&
hdev
->
tx_task
);
hdev
->
notify
(
hdev
,
HCI_NOTIFY_VOICE_SETTING
);
hdev
->
notify
(
hdev
,
HCI_NOTIFY_VOICE_SETTING
);
tasklet_enable
(
&
hdev
->
tx_task
);
}
}
}
static
void
hci_cc_host_buffer_size
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
static
void
hci_cc_host_buffer_size
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
@@ -773,6 +767,28 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -773,6 +767,28 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
hci_req_complete
(
hdev
,
HCI_OP_READ_BD_ADDR
,
rp
->
status
);
hci_req_complete
(
hdev
,
HCI_OP_READ_BD_ADDR
,
rp
->
status
);
}
}
static
void
hci_cc_read_data_block_size
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
struct
hci_rp_read_data_block_size
*
rp
=
(
void
*
)
skb
->
data
;
BT_DBG
(
"%s status 0x%x"
,
hdev
->
name
,
rp
->
status
);
if
(
rp
->
status
)
return
;
hdev
->
block_mtu
=
__le16_to_cpu
(
rp
->
max_acl_len
);
hdev
->
block_len
=
__le16_to_cpu
(
rp
->
block_len
);
hdev
->
num_blocks
=
__le16_to_cpu
(
rp
->
num_blocks
);
hdev
->
block_cnt
=
hdev
->
num_blocks
;
BT_DBG
(
"%s blk mtu %d cnt %d len %d"
,
hdev
->
name
,
hdev
->
block_mtu
,
hdev
->
block_cnt
,
hdev
->
block_len
);
hci_req_complete
(
hdev
,
HCI_OP_READ_DATA_BLOCK_SIZE
,
rp
->
status
);
}
static
void
hci_cc_write_ca_timeout
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
static
void
hci_cc_write_ca_timeout
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
{
__u8
status
=
*
((
__u8
*
)
skb
->
data
);
__u8
status
=
*
((
__u8
*
)
skb
->
data
);
...
@@ -1017,7 +1033,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
...
@@ -1017,7 +1033,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
if
(
cp
->
enable
==
0x01
)
{
if
(
cp
->
enable
==
0x01
)
{
set_bit
(
HCI_LE_SCAN
,
&
hdev
->
dev_flags
);
set_bit
(
HCI_LE_SCAN
,
&
hdev
->
dev_flags
);
del_timer
(
&
hdev
->
adv_timer
);
cancel_delayed_work_sync
(
&
hdev
->
adv_work
);
hci_dev_lock
(
hdev
);
hci_dev_lock
(
hdev
);
hci_adv_entries_clear
(
hdev
);
hci_adv_entries_clear
(
hdev
);
...
@@ -1025,7 +1041,9 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
...
@@ -1025,7 +1041,9 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
}
else
if
(
cp
->
enable
==
0x00
)
{
}
else
if
(
cp
->
enable
==
0x00
)
{
clear_bit
(
HCI_LE_SCAN
,
&
hdev
->
dev_flags
);
clear_bit
(
HCI_LE_SCAN
,
&
hdev
->
dev_flags
);
mod_timer
(
&
hdev
->
adv_timer
,
jiffies
+
ADV_CLEAR_TIMEOUT
);
cancel_delayed_work_sync
(
&
hdev
->
adv_work
);
queue_delayed_work
(
hdev
->
workqueue
,
&
hdev
->
adv_work
,
jiffies
+
ADV_CLEAR_TIMEOUT
);
}
}
}
}
...
@@ -2022,6 +2040,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
...
@@ -2022,6 +2040,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_read_bd_addr
(
hdev
,
skb
);
hci_cc_read_bd_addr
(
hdev
,
skb
);
break
;
break
;
case
HCI_OP_READ_DATA_BLOCK_SIZE
:
hci_cc_read_data_block_size
(
hdev
,
skb
);
break
;
case
HCI_OP_WRITE_CA_TIMEOUT
:
case
HCI_OP_WRITE_CA_TIMEOUT
:
hci_cc_write_ca_timeout
(
hdev
,
skb
);
hci_cc_write_ca_timeout
(
hdev
,
skb
);
break
;
break
;
...
@@ -2116,7 +2138,7 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
...
@@ -2116,7 +2138,7 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
if
(
ev
->
ncmd
)
{
if
(
ev
->
ncmd
)
{
atomic_set
(
&
hdev
->
cmd_cnt
,
1
);
atomic_set
(
&
hdev
->
cmd_cnt
,
1
);
if
(
!
skb_queue_empty
(
&
hdev
->
cmd_q
))
if
(
!
skb_queue_empty
(
&
hdev
->
cmd_q
))
tasklet_schedule
(
&
hdev
->
cmd_tas
k
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
cmd_wor
k
);
}
}
}
}
...
@@ -2198,7 +2220,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -2198,7 +2220,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
if
(
ev
->
ncmd
&&
!
test_bit
(
HCI_RESET
,
&
hdev
->
flags
))
{
if
(
ev
->
ncmd
&&
!
test_bit
(
HCI_RESET
,
&
hdev
->
flags
))
{
atomic_set
(
&
hdev
->
cmd_cnt
,
1
);
atomic_set
(
&
hdev
->
cmd_cnt
,
1
);
if
(
!
skb_queue_empty
(
&
hdev
->
cmd_q
))
if
(
!
skb_queue_empty
(
&
hdev
->
cmd_q
))
tasklet_schedule
(
&
hdev
->
cmd_tas
k
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
cmd_wor
k
);
}
}
}
}
...
@@ -2243,8 +2265,6 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
...
@@ -2243,8 +2265,6 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
return
;
return
;
}
}
tasklet_disable
(
&
hdev
->
tx_task
);
for
(
i
=
0
,
ptr
=
(
__le16
*
)
skb
->
data
;
i
<
ev
->
num_hndl
;
i
++
)
{
for
(
i
=
0
,
ptr
=
(
__le16
*
)
skb
->
data
;
i
<
ev
->
num_hndl
;
i
++
)
{
struct
hci_conn
*
conn
;
struct
hci_conn
*
conn
;
__u16
handle
,
count
;
__u16
handle
,
count
;
...
@@ -2253,14 +2273,19 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
...
@@ -2253,14 +2273,19 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
count
=
get_unaligned_le16
(
ptr
++
);
count
=
get_unaligned_le16
(
ptr
++
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
handle
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
handle
);
if
(
conn
)
{
if
(
!
conn
)
continue
;
conn
->
sent
-=
count
;
conn
->
sent
-=
count
;
if
(
conn
->
type
==
ACL_LINK
)
{
switch
(
conn
->
type
)
{
case
ACL_LINK
:
hdev
->
acl_cnt
+=
count
;
hdev
->
acl_cnt
+=
count
;
if
(
hdev
->
acl_cnt
>
hdev
->
acl_pkts
)
if
(
hdev
->
acl_cnt
>
hdev
->
acl_pkts
)
hdev
->
acl_cnt
=
hdev
->
acl_pkts
;
hdev
->
acl_cnt
=
hdev
->
acl_pkts
;
}
else
if
(
conn
->
type
==
LE_LINK
)
{
break
;
case
LE_LINK
:
if
(
hdev
->
le_pkts
)
{
if
(
hdev
->
le_pkts
)
{
hdev
->
le_cnt
+=
count
;
hdev
->
le_cnt
+=
count
;
if
(
hdev
->
le_cnt
>
hdev
->
le_pkts
)
if
(
hdev
->
le_cnt
>
hdev
->
le_pkts
)
...
@@ -2270,17 +2295,21 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
...
@@ -2270,17 +2295,21 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
if
(
hdev
->
acl_cnt
>
hdev
->
acl_pkts
)
if
(
hdev
->
acl_cnt
>
hdev
->
acl_pkts
)
hdev
->
acl_cnt
=
hdev
->
acl_pkts
;
hdev
->
acl_cnt
=
hdev
->
acl_pkts
;
}
}
}
else
{
break
;
case
SCO_LINK
:
hdev
->
sco_cnt
+=
count
;
hdev
->
sco_cnt
+=
count
;
if
(
hdev
->
sco_cnt
>
hdev
->
sco_pkts
)
if
(
hdev
->
sco_cnt
>
hdev
->
sco_pkts
)
hdev
->
sco_cnt
=
hdev
->
sco_pkts
;
hdev
->
sco_cnt
=
hdev
->
sco_pkts
;
break
;
default:
BT_ERR
(
"Unknown type %d conn %p"
,
conn
->
type
,
conn
);
break
;
}
}
}
}
}
tasklet_schedule
(
&
hdev
->
tx_task
);
tasklet_enable
(
&
hdev
->
tx_tas
k
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
tx_wor
k
);
}
}
static
inline
void
hci_mode_change_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
static
inline
void
hci_mode_change_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
...
...
net/bluetooth/hci_sock.c
View file @
9662cbc7
...
@@ -188,11 +188,11 @@ static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg)
...
@@ -188,11 +188,11 @@ static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg)
if
(
copy_from_user
(
&
bdaddr
,
arg
,
sizeof
(
bdaddr
)))
if
(
copy_from_user
(
&
bdaddr
,
arg
,
sizeof
(
bdaddr
)))
return
-
EFAULT
;
return
-
EFAULT
;
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
err
=
hci_blacklist_add
(
hdev
,
&
bdaddr
);
err
=
hci_blacklist_add
(
hdev
,
&
bdaddr
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
return
err
;
return
err
;
}
}
...
@@ -205,11 +205,11 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
...
@@ -205,11 +205,11 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
if
(
copy_from_user
(
&
bdaddr
,
arg
,
sizeof
(
bdaddr
)))
if
(
copy_from_user
(
&
bdaddr
,
arg
,
sizeof
(
bdaddr
)))
return
-
EFAULT
;
return
-
EFAULT
;
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
err
=
hci_blacklist_del
(
hdev
,
&
bdaddr
);
err
=
hci_blacklist_del
(
hdev
,
&
bdaddr
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
return
err
;
return
err
;
}
}
...
@@ -343,8 +343,11 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
...
@@ -343,8 +343,11 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
if
(
haddr
.
hci_channel
>
HCI_CHANNEL_CONTROL
)
if
(
haddr
.
hci_channel
>
HCI_CHANNEL_CONTROL
)
return
-
EINVAL
;
return
-
EINVAL
;
if
(
haddr
.
hci_channel
==
HCI_CHANNEL_CONTROL
&&
!
enable_mgmt
)
if
(
haddr
.
hci_channel
==
HCI_CHANNEL_CONTROL
)
{
if
(
!
enable_mgmt
)
return
-
EINVAL
;
return
-
EINVAL
;
set_bit
(
HCI_PI_MGMT_INIT
,
&
hci_pi
(
sk
)
->
flags
);
}
lock_sock
(
sk
);
lock_sock
(
sk
);
...
@@ -535,10 +538,10 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
...
@@ -535,10 +538,10 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
if
(
test_bit
(
HCI_RAW
,
&
hdev
->
flags
)
||
(
ogf
==
0x3f
))
{
if
(
test_bit
(
HCI_RAW
,
&
hdev
->
flags
)
||
(
ogf
==
0x3f
))
{
skb_queue_tail
(
&
hdev
->
raw_q
,
skb
);
skb_queue_tail
(
&
hdev
->
raw_q
,
skb
);
tasklet_schedule
(
&
hdev
->
tx_tas
k
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
tx_wor
k
);
}
else
{
}
else
{
skb_queue_tail
(
&
hdev
->
cmd_q
,
skb
);
skb_queue_tail
(
&
hdev
->
cmd_q
,
skb
);
tasklet_schedule
(
&
hdev
->
cmd_tas
k
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
cmd_wor
k
);
}
}
}
else
{
}
else
{
if
(
!
capable
(
CAP_NET_RAW
))
{
if
(
!
capable
(
CAP_NET_RAW
))
{
...
@@ -547,7 +550,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
...
@@ -547,7 +550,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
}
}
skb_queue_tail
(
&
hdev
->
raw_q
,
skb
);
skb_queue_tail
(
&
hdev
->
raw_q
,
skb
);
tasklet_schedule
(
&
hdev
->
tx_tas
k
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
tx_wor
k
);
}
}
err
=
len
;
err
=
len
;
...
...
net/bluetooth/hci_sysfs.c
View file @
9662cbc7
...
@@ -89,11 +89,35 @@ static struct device_type bt_link = {
...
@@ -89,11 +89,35 @@ static struct device_type bt_link = {
.
release
=
bt_link_release
,
.
release
=
bt_link_release
,
};
};
static
void
add_conn
(
struct
work_struct
*
work
)
/*
* The rfcomm tty device will possibly retain even when conn
* is down, and sysfs doesn't support move zombie device,
* so we should move the device before conn device is destroyed.
*/
static
int
__match_tty
(
struct
device
*
dev
,
void
*
data
)
{
return
!
strncmp
(
dev_name
(
dev
),
"rfcomm"
,
6
);
}
void
hci_conn_init_sysfs
(
struct
hci_conn
*
conn
)
{
struct
hci_dev
*
hdev
=
conn
->
hdev
;
BT_DBG
(
"conn %p"
,
conn
);
conn
->
dev
.
type
=
&
bt_link
;
conn
->
dev
.
class
=
bt_class
;
conn
->
dev
.
parent
=
&
hdev
->
dev
;
device_initialize
(
&
conn
->
dev
);
}
void
hci_conn_add_sysfs
(
struct
hci_conn
*
conn
)
{
{
struct
hci_conn
*
conn
=
container_of
(
work
,
struct
hci_conn
,
work_add
);
struct
hci_dev
*
hdev
=
conn
->
hdev
;
struct
hci_dev
*
hdev
=
conn
->
hdev
;
BT_DBG
(
"conn %p"
,
conn
);
dev_set_name
(
&
conn
->
dev
,
"%s:%d"
,
hdev
->
name
,
conn
->
handle
);
dev_set_name
(
&
conn
->
dev
,
"%s:%d"
,
hdev
->
name
,
conn
->
handle
);
dev_set_drvdata
(
&
conn
->
dev
,
conn
);
dev_set_drvdata
(
&
conn
->
dev
,
conn
);
...
@@ -106,19 +130,8 @@ static void add_conn(struct work_struct *work)
...
@@ -106,19 +130,8 @@ static void add_conn(struct work_struct *work)
hci_dev_hold
(
hdev
);
hci_dev_hold
(
hdev
);
}
}
/*
void
hci_conn_del_sysfs
(
struct
hci_conn
*
conn
)
* The rfcomm tty device will possibly retain even when conn
* is down, and sysfs doesn't support move zombie device,
* so we should move the device before conn device is destroyed.
*/
static
int
__match_tty
(
struct
device
*
dev
,
void
*
data
)
{
return
!
strncmp
(
dev_name
(
dev
),
"rfcomm"
,
6
);
}
static
void
del_conn
(
struct
work_struct
*
work
)
{
{
struct
hci_conn
*
conn
=
container_of
(
work
,
struct
hci_conn
,
work_del
);
struct
hci_dev
*
hdev
=
conn
->
hdev
;
struct
hci_dev
*
hdev
=
conn
->
hdev
;
if
(
!
device_is_registered
(
&
conn
->
dev
))
if
(
!
device_is_registered
(
&
conn
->
dev
))
...
@@ -140,36 +153,6 @@ static void del_conn(struct work_struct *work)
...
@@ -140,36 +153,6 @@ static void del_conn(struct work_struct *work)
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
}
}
void
hci_conn_init_sysfs
(
struct
hci_conn
*
conn
)
{
struct
hci_dev
*
hdev
=
conn
->
hdev
;
BT_DBG
(
"conn %p"
,
conn
);
conn
->
dev
.
type
=
&
bt_link
;
conn
->
dev
.
class
=
bt_class
;
conn
->
dev
.
parent
=
&
hdev
->
dev
;
device_initialize
(
&
conn
->
dev
);
INIT_WORK
(
&
conn
->
work_add
,
add_conn
);
INIT_WORK
(
&
conn
->
work_del
,
del_conn
);
}
void
hci_conn_add_sysfs
(
struct
hci_conn
*
conn
)
{
BT_DBG
(
"conn %p"
,
conn
);
queue_work
(
conn
->
hdev
->
workqueue
,
&
conn
->
work_add
);
}
void
hci_conn_del_sysfs
(
struct
hci_conn
*
conn
)
{
BT_DBG
(
"conn %p"
,
conn
);
queue_work
(
conn
->
hdev
->
workqueue
,
&
conn
->
work_del
);
}
static
inline
char
*
host_bustostr
(
int
bus
)
static
inline
char
*
host_bustostr
(
int
bus
)
{
{
switch
(
bus
)
{
switch
(
bus
)
{
...
@@ -403,7 +386,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p)
...
@@ -403,7 +386,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p)
struct
inquiry_cache
*
cache
=
&
hdev
->
inq_cache
;
struct
inquiry_cache
*
cache
=
&
hdev
->
inq_cache
;
struct
inquiry_entry
*
e
;
struct
inquiry_entry
*
e
;
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
for
(
e
=
cache
->
list
;
e
;
e
=
e
->
next
)
{
for
(
e
=
cache
->
list
;
e
;
e
=
e
->
next
)
{
struct
inquiry_data
*
data
=
&
e
->
data
;
struct
inquiry_data
*
data
=
&
e
->
data
;
...
@@ -416,7 +399,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p)
...
@@ -416,7 +399,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p)
data
->
rssi
,
data
->
ssp_mode
,
e
->
timestamp
);
data
->
rssi
,
data
->
ssp_mode
,
e
->
timestamp
);
}
}
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
return
0
;
return
0
;
}
}
...
@@ -438,12 +421,12 @@ static int blacklist_show(struct seq_file *f, void *p)
...
@@ -438,12 +421,12 @@ static int blacklist_show(struct seq_file *f, void *p)
struct
hci_dev
*
hdev
=
f
->
private
;
struct
hci_dev
*
hdev
=
f
->
private
;
struct
bdaddr_list
*
b
;
struct
bdaddr_list
*
b
;
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
list_for_each_entry
(
b
,
&
hdev
->
blacklist
,
list
)
list_for_each_entry
(
b
,
&
hdev
->
blacklist
,
list
)
seq_printf
(
f
,
"%s
\n
"
,
batostr
(
&
b
->
bdaddr
));
seq_printf
(
f
,
"%s
\n
"
,
batostr
(
&
b
->
bdaddr
));
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
return
0
;
return
0
;
}
}
...
@@ -482,12 +465,12 @@ static int uuids_show(struct seq_file *f, void *p)
...
@@ -482,12 +465,12 @@ static int uuids_show(struct seq_file *f, void *p)
struct
hci_dev
*
hdev
=
f
->
private
;
struct
hci_dev
*
hdev
=
f
->
private
;
struct
bt_uuid
*
uuid
;
struct
bt_uuid
*
uuid
;
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
list_for_each_entry
(
uuid
,
&
hdev
->
uuids
,
list
)
list_for_each_entry
(
uuid
,
&
hdev
->
uuids
,
list
)
print_bt_uuid
(
f
,
uuid
->
uuid
);
print_bt_uuid
(
f
,
uuid
->
uuid
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
return
0
;
return
0
;
}
}
...
@@ -508,11 +491,11 @@ static int auto_accept_delay_set(void *data, u64 val)
...
@@ -508,11 +491,11 @@ static int auto_accept_delay_set(void *data, u64 val)
{
{
struct
hci_dev
*
hdev
=
data
;
struct
hci_dev
*
hdev
=
data
;
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
hdev
->
auto_accept_delay
=
val
;
hdev
->
auto_accept_delay
=
val
;
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
return
0
;
return
0
;
}
}
...
@@ -521,11 +504,11 @@ static int auto_accept_delay_get(void *data, u64 *val)
...
@@ -521,11 +504,11 @@ static int auto_accept_delay_get(void *data, u64 *val)
{
{
struct
hci_dev
*
hdev
=
data
;
struct
hci_dev
*
hdev
=
data
;
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
*
val
=
hdev
->
auto_accept_delay
;
*
val
=
hdev
->
auto_accept_delay
;
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
return
0
;
return
0
;
}
}
...
...
net/bluetooth/hidp/core.c
View file @
9662cbc7
...
@@ -795,11 +795,11 @@ static struct hci_conn *hidp_get_connection(struct hidp_session *session)
...
@@ -795,11 +795,11 @@ static struct hci_conn *hidp_get_connection(struct hidp_session *session)
if
(
!
hdev
)
if
(
!
hdev
)
return
NULL
;
return
NULL
;
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
ACL_LINK
,
dst
);
conn
=
hci_conn_hash_lookup_ba
(
hdev
,
ACL_LINK
,
dst
);
if
(
conn
)
if
(
conn
)
hci_conn_hold_device
(
conn
);
hci_conn_hold_device
(
conn
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
...
...
net/bluetooth/l2cap_core.c
View file @
9662cbc7
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
Copyright (C) 2000-2001 Qualcomm Incorporated
Copyright (C) 2000-2001 Qualcomm Incorporated
Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Copyright (C) 2010 Google Inc.
Copyright (C) 2010 Google Inc.
Copyright (C) 2011 ProFUSION Embedded Systems
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
...
@@ -89,24 +90,36 @@ static inline void chan_put(struct l2cap_chan *c)
...
@@ -89,24 +90,36 @@ static inline void chan_put(struct l2cap_chan *c)
static
struct
l2cap_chan
*
__l2cap_get_chan_by_dcid
(
struct
l2cap_conn
*
conn
,
u16
cid
)
static
struct
l2cap_chan
*
__l2cap_get_chan_by_dcid
(
struct
l2cap_conn
*
conn
,
u16
cid
)
{
{
struct
l2cap_chan
*
c
;
struct
l2cap_chan
*
c
,
*
r
=
NULL
;
list_for_each_entry
(
c
,
&
conn
->
chan_l
,
list
)
{
rcu_read_lock
();
if
(
c
->
dcid
==
cid
)
return
c
;
list_for_each_entry_rcu
(
c
,
&
conn
->
chan_l
,
list
)
{
if
(
c
->
dcid
==
cid
)
{
r
=
c
;
break
;
}
}
return
NULL
;
}
rcu_read_unlock
();
return
r
;
}
}
static
struct
l2cap_chan
*
__l2cap_get_chan_by_scid
(
struct
l2cap_conn
*
conn
,
u16
cid
)
static
struct
l2cap_chan
*
__l2cap_get_chan_by_scid
(
struct
l2cap_conn
*
conn
,
u16
cid
)
{
{
struct
l2cap_chan
*
c
;
struct
l2cap_chan
*
c
,
*
r
=
NULL
;
list_for_each_entry
(
c
,
&
conn
->
chan_l
,
list
)
{
rcu_read_lock
();
if
(
c
->
scid
==
cid
)
return
c
;
list_for_each_entry_rcu
(
c
,
&
conn
->
chan_l
,
list
)
{
if
(
c
->
scid
==
cid
)
{
r
=
c
;
break
;
}
}
return
NULL
;
}
rcu_read_unlock
();
return
r
;
}
}
/* Find channel with given SCID.
/* Find channel with given SCID.
...
@@ -115,34 +128,36 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci
...
@@ -115,34 +128,36 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci
{
{
struct
l2cap_chan
*
c
;
struct
l2cap_chan
*
c
;
read_lock
(
&
conn
->
chan_lock
);
c
=
__l2cap_get_chan_by_scid
(
conn
,
cid
);
c
=
__l2cap_get_chan_by_scid
(
conn
,
cid
);
if
(
c
)
if
(
c
)
bh_lock_sock
(
c
->
sk
);
lock_sock
(
c
->
sk
);
read_unlock
(
&
conn
->
chan_lock
);
return
c
;
return
c
;
}
}
static
struct
l2cap_chan
*
__l2cap_get_chan_by_ident
(
struct
l2cap_conn
*
conn
,
u8
ident
)
static
struct
l2cap_chan
*
__l2cap_get_chan_by_ident
(
struct
l2cap_conn
*
conn
,
u8
ident
)
{
{
struct
l2cap_chan
*
c
;
struct
l2cap_chan
*
c
,
*
r
=
NULL
;
list_for_each_entry
(
c
,
&
conn
->
chan_l
,
list
)
{
rcu_read_lock
();
if
(
c
->
ident
==
ident
)
return
c
;
list_for_each_entry_rcu
(
c
,
&
conn
->
chan_l
,
list
)
{
if
(
c
->
ident
==
ident
)
{
r
=
c
;
break
;
}
}
return
NULL
;
}
rcu_read_unlock
();
return
r
;
}
}
static
inline
struct
l2cap_chan
*
l2cap_get_chan_by_ident
(
struct
l2cap_conn
*
conn
,
u8
ident
)
static
inline
struct
l2cap_chan
*
l2cap_get_chan_by_ident
(
struct
l2cap_conn
*
conn
,
u8
ident
)
{
{
struct
l2cap_chan
*
c
;
struct
l2cap_chan
*
c
;
read_lock
(
&
conn
->
chan_lock
);
c
=
__l2cap_get_chan_by_ident
(
conn
,
ident
);
c
=
__l2cap_get_chan_by_ident
(
conn
,
ident
);
if
(
c
)
if
(
c
)
bh_lock_sock
(
c
->
sk
);
lock_sock
(
c
->
sk
);
read_unlock
(
&
conn
->
chan_lock
);
return
c
;
return
c
;
}
}
...
@@ -213,20 +228,18 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
...
@@ -213,20 +228,18 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
return
0
;
return
0
;
}
}
static
void
l2cap_set_timer
(
struct
l2cap_chan
*
chan
,
struct
timer_list
*
timer
,
long
timeout
)
static
void
l2cap_set_timer
(
struct
l2cap_chan
*
chan
,
struct
delayed_work
*
work
,
long
timeout
)
{
{
BT_DBG
(
"chan %p state %d timeout %ld"
,
chan
,
chan
->
state
,
timeout
);
BT_DBG
(
"chan %p state %d timeout %ld"
,
chan
,
chan
->
state
,
timeout
);
if
(
!
mod_timer
(
timer
,
jiffies
+
msecs_to_jiffies
(
timeout
)))
cancel_delayed_work_sync
(
work
);
chan_hold
(
chan
);
schedule_delayed_work
(
work
,
timeout
);
}
}
static
void
l2cap_clear_timer
(
struct
l2cap_chan
*
chan
,
struct
timer_list
*
timer
)
static
void
l2cap_clear_timer
(
struct
delayed_work
*
work
)
{
{
BT_DBG
(
"chan %p state %d"
,
chan
,
chan
->
state
);
cancel_delayed_work_sync
(
work
);
if
(
timer_pending
(
timer
)
&&
del_timer
(
timer
))
chan_put
(
chan
);
}
}
static
char
*
state_to_string
(
int
state
)
static
char
*
state_to_string
(
int
state
)
...
@@ -264,23 +277,16 @@ static void l2cap_state_change(struct l2cap_chan *chan, int state)
...
@@ -264,23 +277,16 @@ static void l2cap_state_change(struct l2cap_chan *chan, int state)
chan
->
ops
->
state_change
(
chan
->
data
,
state
);
chan
->
ops
->
state_change
(
chan
->
data
,
state
);
}
}
static
void
l2cap_chan_timeout
(
unsigned
long
arg
)
static
void
l2cap_chan_timeout
(
struct
work_struct
*
work
)
{
{
struct
l2cap_chan
*
chan
=
(
struct
l2cap_chan
*
)
arg
;
struct
l2cap_chan
*
chan
=
container_of
(
work
,
struct
l2cap_chan
,
chan_timer
.
work
);
struct
sock
*
sk
=
chan
->
sk
;
struct
sock
*
sk
=
chan
->
sk
;
int
reason
;
int
reason
;
BT_DBG
(
"chan %p state %d"
,
chan
,
chan
->
state
);
BT_DBG
(
"chan %p state %d"
,
chan
,
chan
->
state
);
bh_lock_sock
(
sk
);
lock_sock
(
sk
);
if
(
sock_owned_by_user
(
sk
))
{
/* sk is owned by user. Try again later */
__set_chan_timer
(
chan
,
L2CAP_DISC_TIMEOUT
);
bh_unlock_sock
(
sk
);
chan_put
(
chan
);
return
;
}
if
(
chan
->
state
==
BT_CONNECTED
||
chan
->
state
==
BT_CONFIG
)
if
(
chan
->
state
==
BT_CONNECTED
||
chan
->
state
==
BT_CONFIG
)
reason
=
ECONNREFUSED
;
reason
=
ECONNREFUSED
;
...
@@ -292,7 +298,7 @@ static void l2cap_chan_timeout(unsigned long arg)
...
@@ -292,7 +298,7 @@ static void l2cap_chan_timeout(unsigned long arg)
l2cap_chan_close
(
chan
,
reason
);
l2cap_chan_close
(
chan
,
reason
);
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
chan
->
ops
->
close
(
chan
->
data
);
chan
->
ops
->
close
(
chan
->
data
);
chan_put
(
chan
);
chan_put
(
chan
);
...
@@ -312,7 +318,7 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
...
@@ -312,7 +318,7 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
list_add
(
&
chan
->
global_l
,
&
chan_list
);
list_add
(
&
chan
->
global_l
,
&
chan_list
);
write_unlock_bh
(
&
chan_list_lock
);
write_unlock_bh
(
&
chan_list_lock
);
setup_timer
(
&
chan
->
chan_timer
,
l2cap_chan_timeout
,
(
unsigned
long
)
chan
);
INIT_DELAYED_WORK
(
&
chan
->
chan_timer
,
l2cap_chan_timeout
);
chan
->
state
=
BT_OPEN
;
chan
->
state
=
BT_OPEN
;
...
@@ -332,7 +338,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan)
...
@@ -332,7 +338,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan)
chan_put
(
chan
);
chan_put
(
chan
);
}
}
static
void
__
l2cap_chan_add
(
struct
l2cap_conn
*
conn
,
struct
l2cap_chan
*
chan
)
static
void
l2cap_chan_add
(
struct
l2cap_conn
*
conn
,
struct
l2cap_chan
*
chan
)
{
{
BT_DBG
(
"conn %p, psm 0x%2.2x, dcid 0x%4.4x"
,
conn
,
BT_DBG
(
"conn %p, psm 0x%2.2x, dcid 0x%4.4x"
,
conn
,
chan
->
psm
,
chan
->
dcid
);
chan
->
psm
,
chan
->
dcid
);
...
@@ -373,7 +379,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
...
@@ -373,7 +379,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
chan_hold
(
chan
);
chan_hold
(
chan
);
list_add
(
&
chan
->
list
,
&
conn
->
chan_l
);
list_add
_rcu
(
&
chan
->
list
,
&
conn
->
chan_l
);
}
}
/* Delete channel.
/* Delete channel.
...
@@ -390,9 +396,9 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
...
@@ -390,9 +396,9 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
if
(
conn
)
{
if
(
conn
)
{
/* Delete from channel list */
/* Delete from channel list */
write_lock_bh
(
&
conn
->
chan_lock
);
list_del_rcu
(
&
chan
->
list
);
list_del
(
&
chan
->
list
);
synchronize_rcu
(
);
write_unlock_bh
(
&
conn
->
chan_lock
);
chan_put
(
chan
);
chan_put
(
chan
);
chan
->
conn
=
NULL
;
chan
->
conn
=
NULL
;
...
@@ -707,7 +713,7 @@ static void l2cap_do_start(struct l2cap_chan *chan)
...
@@ -707,7 +713,7 @@ static void l2cap_do_start(struct l2cap_chan *chan)
conn
->
info_state
|=
L2CAP_INFO_FEAT_MASK_REQ_SENT
;
conn
->
info_state
|=
L2CAP_INFO_FEAT_MASK_REQ_SENT
;
conn
->
info_ident
=
l2cap_get_ident
(
conn
);
conn
->
info_ident
=
l2cap_get_ident
(
conn
);
mod_timer
(
&
conn
->
info_timer
,
jiffies
+
schedule_delayed_work
(
&
conn
->
info_work
,
msecs_to_jiffies
(
L2CAP_INFO_TIMEOUT
));
msecs_to_jiffies
(
L2CAP_INFO_TIMEOUT
));
l2cap_send_cmd
(
conn
,
conn
->
info_ident
,
l2cap_send_cmd
(
conn
,
conn
->
info_ident
,
...
@@ -759,13 +765,13 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
...
@@ -759,13 +765,13 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
/* ---- L2CAP connections ---- */
/* ---- L2CAP connections ---- */
static
void
l2cap_conn_start
(
struct
l2cap_conn
*
conn
)
static
void
l2cap_conn_start
(
struct
l2cap_conn
*
conn
)
{
{
struct
l2cap_chan
*
chan
,
*
tmp
;
struct
l2cap_chan
*
chan
;
BT_DBG
(
"conn %p"
,
conn
);
BT_DBG
(
"conn %p"
,
conn
);
r
ead_lock
(
&
conn
->
chan_lock
);
r
cu_read_lock
(
);
list_for_each_entry_
safe
(
chan
,
tmp
,
&
conn
->
chan_l
,
list
)
{
list_for_each_entry_
rcu
(
chan
,
&
conn
->
chan_l
,
list
)
{
struct
sock
*
sk
=
chan
->
sk
;
struct
sock
*
sk
=
chan
->
sk
;
bh_lock_sock
(
sk
);
bh_lock_sock
(
sk
);
...
@@ -789,9 +795,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
...
@@ -789,9 +795,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
&
chan
->
conf_state
))
{
&
chan
->
conf_state
))
{
/* l2cap_chan_close() calls list_del(chan)
/* l2cap_chan_close() calls list_del(chan)
* so release the lock */
* so release the lock */
read_unlock
(
&
conn
->
chan_lock
);
l2cap_chan_close
(
chan
,
ECONNRESET
);
l2cap_chan_close
(
chan
,
ECONNRESET
);
read_lock
(
&
conn
->
chan_lock
);
bh_unlock_sock
(
sk
);
bh_unlock_sock
(
sk
);
continue
;
continue
;
}
}
...
@@ -847,7 +851,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
...
@@ -847,7 +851,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
bh_unlock_sock
(
sk
);
bh_unlock_sock
(
sk
);
}
}
r
ead_unlock
(
&
conn
->
chan_lock
);
r
cu_read_unlock
(
);
}
}
/* Find socket with cid and source bdaddr.
/* Find socket with cid and source bdaddr.
...
@@ -898,7 +902,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
...
@@ -898,7 +902,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
parent
=
pchan
->
sk
;
parent
=
pchan
->
sk
;
bh_
lock_sock
(
parent
);
lock_sock
(
parent
);
/* Check for backlog size */
/* Check for backlog size */
if
(
sk_acceptq_is_full
(
parent
))
{
if
(
sk_acceptq_is_full
(
parent
))
{
...
@@ -912,8 +916,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
...
@@ -912,8 +916,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
sk
=
chan
->
sk
;
sk
=
chan
->
sk
;
write_lock_bh
(
&
conn
->
chan_lock
);
hci_conn_hold
(
conn
->
hcon
);
hci_conn_hold
(
conn
->
hcon
);
bacpy
(
&
bt_sk
(
sk
)
->
src
,
conn
->
src
);
bacpy
(
&
bt_sk
(
sk
)
->
src
,
conn
->
src
);
...
@@ -921,17 +923,15 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
...
@@ -921,17 +923,15 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
bt_accept_enqueue
(
parent
,
sk
);
bt_accept_enqueue
(
parent
,
sk
);
__
l2cap_chan_add
(
conn
,
chan
);
l2cap_chan_add
(
conn
,
chan
);
__set_chan_timer
(
chan
,
sk
->
sk_sndtimeo
);
__set_chan_timer
(
chan
,
sk
->
sk_sndtimeo
);
l2cap_state_change
(
chan
,
BT_CONNECTED
);
l2cap_state_change
(
chan
,
BT_CONNECTED
);
parent
->
sk_data_ready
(
parent
,
0
);
parent
->
sk_data_ready
(
parent
,
0
);
write_unlock_bh
(
&
conn
->
chan_lock
);
clean:
clean:
bh_unlock
_sock
(
parent
);
release
_sock
(
parent
);
}
}
static
void
l2cap_chan_ready
(
struct
sock
*
sk
)
static
void
l2cap_chan_ready
(
struct
sock
*
sk
)
...
@@ -963,9 +963,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
...
@@ -963,9 +963,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
if
(
conn
->
hcon
->
out
&&
conn
->
hcon
->
type
==
LE_LINK
)
if
(
conn
->
hcon
->
out
&&
conn
->
hcon
->
type
==
LE_LINK
)
smp_conn_security
(
conn
,
conn
->
hcon
->
pending_sec_level
);
smp_conn_security
(
conn
,
conn
->
hcon
->
pending_sec_level
);
r
ead_lock
(
&
conn
->
chan_lock
);
r
cu_read_lock
(
);
list_for_each_entry
(
chan
,
&
conn
->
chan_l
,
list
)
{
list_for_each_entry
_rcu
(
chan
,
&
conn
->
chan_l
,
list
)
{
struct
sock
*
sk
=
chan
->
sk
;
struct
sock
*
sk
=
chan
->
sk
;
bh_lock_sock
(
sk
);
bh_lock_sock
(
sk
);
...
@@ -985,7 +985,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
...
@@ -985,7 +985,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
bh_unlock_sock
(
sk
);
bh_unlock_sock
(
sk
);
}
}
r
ead_unlock
(
&
conn
->
chan_lock
);
r
cu_read_unlock
(
);
}
}
/* Notify sockets that we cannot guaranty reliability anymore */
/* Notify sockets that we cannot guaranty reliability anymore */
...
@@ -995,21 +995,22 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
...
@@ -995,21 +995,22 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
BT_DBG
(
"conn %p"
,
conn
);
BT_DBG
(
"conn %p"
,
conn
);
r
ead_lock
(
&
conn
->
chan_lock
);
r
cu_read_lock
(
);
list_for_each_entry
(
chan
,
&
conn
->
chan_l
,
list
)
{
list_for_each_entry
_rcu
(
chan
,
&
conn
->
chan_l
,
list
)
{
struct
sock
*
sk
=
chan
->
sk
;
struct
sock
*
sk
=
chan
->
sk
;
if
(
test_bit
(
FLAG_FORCE_RELIABLE
,
&
chan
->
flags
))
if
(
test_bit
(
FLAG_FORCE_RELIABLE
,
&
chan
->
flags
))
sk
->
sk_err
=
err
;
sk
->
sk_err
=
err
;
}
}
r
ead_unlock
(
&
conn
->
chan_lock
);
r
cu_read_unlock
(
);
}
}
static
void
l2cap_info_timeout
(
unsigned
long
arg
)
static
void
l2cap_info_timeout
(
struct
work_struct
*
work
)
{
{
struct
l2cap_conn
*
conn
=
(
void
*
)
arg
;
struct
l2cap_conn
*
conn
=
container_of
(
work
,
struct
l2cap_conn
,
info_work
.
work
);
conn
->
info_state
|=
L2CAP_INFO_FEAT_MASK_REQ_DONE
;
conn
->
info_state
|=
L2CAP_INFO_FEAT_MASK_REQ_DONE
;
conn
->
info_ident
=
0
;
conn
->
info_ident
=
0
;
...
@@ -1033,16 +1034,16 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
...
@@ -1033,16 +1034,16 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
/* Kill channels */
/* Kill channels */
list_for_each_entry_safe
(
chan
,
l
,
&
conn
->
chan_l
,
list
)
{
list_for_each_entry_safe
(
chan
,
l
,
&
conn
->
chan_l
,
list
)
{
sk
=
chan
->
sk
;
sk
=
chan
->
sk
;
bh_
lock_sock
(
sk
);
lock_sock
(
sk
);
l2cap_chan_del
(
chan
,
err
);
l2cap_chan_del
(
chan
,
err
);
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
chan
->
ops
->
close
(
chan
->
data
);
chan
->
ops
->
close
(
chan
->
data
);
}
}
hci_chan_del
(
conn
->
hchan
);
hci_chan_del
(
conn
->
hchan
);
if
(
conn
->
info_state
&
L2CAP_INFO_FEAT_MASK_REQ_SENT
)
if
(
conn
->
info_state
&
L2CAP_INFO_FEAT_MASK_REQ_SENT
)
del_timer_sync
(
&
conn
->
info_timer
);
cancel_delayed_work_sync
(
&
conn
->
info_work
);
if
(
test_and_clear_bit
(
HCI_CONN_LE_SMP_PEND
,
&
hcon
->
pend
))
{
if
(
test_and_clear_bit
(
HCI_CONN_LE_SMP_PEND
,
&
hcon
->
pend
))
{
del_timer
(
&
conn
->
security_timer
);
del_timer
(
&
conn
->
security_timer
);
...
@@ -1095,7 +1096,6 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
...
@@ -1095,7 +1096,6 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
conn
->
feat_mask
=
0
;
conn
->
feat_mask
=
0
;
spin_lock_init
(
&
conn
->
lock
);
spin_lock_init
(
&
conn
->
lock
);
rwlock_init
(
&
conn
->
chan_lock
);
INIT_LIST_HEAD
(
&
conn
->
chan_l
);
INIT_LIST_HEAD
(
&
conn
->
chan_l
);
...
@@ -1103,21 +1103,13 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
...
@@ -1103,21 +1103,13 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
setup_timer
(
&
conn
->
security_timer
,
security_timeout
,
setup_timer
(
&
conn
->
security_timer
,
security_timeout
,
(
unsigned
long
)
conn
);
(
unsigned
long
)
conn
);
else
else
setup_timer
(
&
conn
->
info_timer
,
l2cap_info_timeout
,
INIT_DELAYED_WORK
(
&
conn
->
info_work
,
l2cap_info_timeout
);
(
unsigned
long
)
conn
);
conn
->
disc_reason
=
HCI_ERROR_REMOTE_USER_TERM
;
conn
->
disc_reason
=
HCI_ERROR_REMOTE_USER_TERM
;
return
conn
;
return
conn
;
}
}
static
inline
void
l2cap_chan_add
(
struct
l2cap_conn
*
conn
,
struct
l2cap_chan
*
chan
)
{
write_lock_bh
(
&
conn
->
chan_lock
);
__l2cap_chan_add
(
conn
,
chan
);
write_unlock_bh
(
&
conn
->
chan_lock
);
}
/* ---- Socket interface ---- */
/* ---- Socket interface ---- */
/* Find socket with psm and source bdaddr.
/* Find socket with psm and source bdaddr.
...
@@ -1153,11 +1145,10 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr
...
@@ -1153,11 +1145,10 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr
return
c1
;
return
c1
;
}
}
in
t
l2cap_chan_connect
(
struct
l2cap_chan
*
chan
)
in
line
int
l2cap_chan_connect
(
struct
l2cap_chan
*
chan
,
__le16
psm
,
u16
cid
,
bdaddr_t
*
dst
)
{
{
struct
sock
*
sk
=
chan
->
sk
;
struct
sock
*
sk
=
chan
->
sk
;
bdaddr_t
*
src
=
&
bt_sk
(
sk
)
->
src
;
bdaddr_t
*
src
=
&
bt_sk
(
sk
)
->
src
;
bdaddr_t
*
dst
=
&
bt_sk
(
sk
)
->
dst
;
struct
l2cap_conn
*
conn
;
struct
l2cap_conn
*
conn
;
struct
hci_conn
*
hcon
;
struct
hci_conn
*
hcon
;
struct
hci_dev
*
hdev
;
struct
hci_dev
*
hdev
;
...
@@ -1171,7 +1162,62 @@ int l2cap_chan_connect(struct l2cap_chan *chan)
...
@@ -1171,7 +1162,62 @@ int l2cap_chan_connect(struct l2cap_chan *chan)
if
(
!
hdev
)
if
(
!
hdev
)
return
-
EHOSTUNREACH
;
return
-
EHOSTUNREACH
;
hci_dev_lock_bh
(
hdev
);
hci_dev_lock
(
hdev
);
lock_sock
(
sk
);
/* PSM must be odd and lsb of upper byte must be 0 */
if
((
__le16_to_cpu
(
psm
)
&
0x0101
)
!=
0x0001
&&
!
cid
&&
chan
->
chan_type
!=
L2CAP_CHAN_RAW
)
{
err
=
-
EINVAL
;
goto
done
;
}
if
(
chan
->
chan_type
==
L2CAP_CHAN_CONN_ORIENTED
&&
!
(
psm
||
cid
))
{
err
=
-
EINVAL
;
goto
done
;
}
switch
(
chan
->
mode
)
{
case
L2CAP_MODE_BASIC
:
break
;
case
L2CAP_MODE_ERTM
:
case
L2CAP_MODE_STREAMING
:
if
(
!
disable_ertm
)
break
;
/* fall through */
default:
err
=
-
ENOTSUPP
;
goto
done
;
}
switch
(
sk
->
sk_state
)
{
case
BT_CONNECT
:
case
BT_CONNECT2
:
case
BT_CONFIG
:
/* Already connecting */
err
=
0
;
goto
done
;
case
BT_CONNECTED
:
/* Already connected */
err
=
-
EISCONN
;
goto
done
;
case
BT_OPEN
:
case
BT_BOUND
:
/* Can connect */
break
;
default:
err
=
-
EBADFD
;
goto
done
;
}
/* Set destination address and psm */
bacpy
(
&
bt_sk
(
sk
)
->
dst
,
src
);
chan
->
psm
=
psm
;
chan
->
dcid
=
cid
;
auth_type
=
l2cap_get_auth_type
(
chan
);
auth_type
=
l2cap_get_auth_type
(
chan
);
...
@@ -1214,7 +1260,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan)
...
@@ -1214,7 +1260,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan)
err
=
0
;
err
=
0
;
done:
done:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
}
}
...
@@ -1251,17 +1297,18 @@ int __l2cap_wait_ack(struct sock *sk)
...
@@ -1251,17 +1297,18 @@ int __l2cap_wait_ack(struct sock *sk)
return
err
;
return
err
;
}
}
static
void
l2cap_monitor_timeout
(
unsigned
long
arg
)
static
void
l2cap_monitor_timeout
(
struct
work_struct
*
work
)
{
{
struct
l2cap_chan
*
chan
=
(
void
*
)
arg
;
struct
l2cap_chan
*
chan
=
container_of
(
work
,
struct
l2cap_chan
,
monitor_timer
.
work
);
struct
sock
*
sk
=
chan
->
sk
;
struct
sock
*
sk
=
chan
->
sk
;
BT_DBG
(
"chan %p"
,
chan
);
BT_DBG
(
"chan %p"
,
chan
);
bh_
lock_sock
(
sk
);
lock_sock
(
sk
);
if
(
chan
->
retry_count
>=
chan
->
remote_max_tx
)
{
if
(
chan
->
retry_count
>=
chan
->
remote_max_tx
)
{
l2cap_send_disconn_req
(
chan
->
conn
,
chan
,
ECONNABORTED
);
l2cap_send_disconn_req
(
chan
->
conn
,
chan
,
ECONNABORTED
);
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
return
;
return
;
}
}
...
@@ -1269,24 +1316,25 @@ static void l2cap_monitor_timeout(unsigned long arg)
...
@@ -1269,24 +1316,25 @@ static void l2cap_monitor_timeout(unsigned long arg)
__set_monitor_timer
(
chan
);
__set_monitor_timer
(
chan
);
l2cap_send_rr_or_rnr
(
chan
,
L2CAP_CTRL_POLL
);
l2cap_send_rr_or_rnr
(
chan
,
L2CAP_CTRL_POLL
);
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
}
}
static
void
l2cap_retrans_timeout
(
unsigned
long
arg
)
static
void
l2cap_retrans_timeout
(
struct
work_struct
*
work
)
{
{
struct
l2cap_chan
*
chan
=
(
void
*
)
arg
;
struct
l2cap_chan
*
chan
=
container_of
(
work
,
struct
l2cap_chan
,
retrans_timer
.
work
);
struct
sock
*
sk
=
chan
->
sk
;
struct
sock
*
sk
=
chan
->
sk
;
BT_DBG
(
"chan %p"
,
chan
);
BT_DBG
(
"chan %p"
,
chan
);
bh_
lock_sock
(
sk
);
lock_sock
(
sk
);
chan
->
retry_count
=
1
;
chan
->
retry_count
=
1
;
__set_monitor_timer
(
chan
);
__set_monitor_timer
(
chan
);
set_bit
(
CONN_WAIT_F
,
&
chan
->
conn_state
);
set_bit
(
CONN_WAIT_F
,
&
chan
->
conn_state
);
l2cap_send_rr_or_rnr
(
chan
,
L2CAP_CTRL_POLL
);
l2cap_send_rr_or_rnr
(
chan
,
L2CAP_CTRL_POLL
);
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
}
}
static
void
l2cap_drop_acked_frames
(
struct
l2cap_chan
*
chan
)
static
void
l2cap_drop_acked_frames
(
struct
l2cap_chan
*
chan
)
...
@@ -1778,8 +1826,9 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
...
@@ -1778,8 +1826,9 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
BT_DBG
(
"conn %p"
,
conn
);
BT_DBG
(
"conn %p"
,
conn
);
read_lock
(
&
conn
->
chan_lock
);
rcu_read_lock
();
list_for_each_entry
(
chan
,
&
conn
->
chan_l
,
list
)
{
list_for_each_entry_rcu
(
chan
,
&
conn
->
chan_l
,
list
)
{
struct
sock
*
sk
=
chan
->
sk
;
struct
sock
*
sk
=
chan
->
sk
;
if
(
chan
->
chan_type
!=
L2CAP_CHAN_RAW
)
if
(
chan
->
chan_type
!=
L2CAP_CHAN_RAW
)
continue
;
continue
;
...
@@ -1794,7 +1843,8 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
...
@@ -1794,7 +1843,8 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
if
(
chan
->
ops
->
recv
(
chan
->
data
,
nskb
))
if
(
chan
->
ops
->
recv
(
chan
->
data
,
nskb
))
kfree_skb
(
nskb
);
kfree_skb
(
nskb
);
}
}
read_unlock
(
&
conn
->
chan_lock
);
rcu_read_unlock
();
}
}
/* ---- L2CAP signalling commands ---- */
/* ---- L2CAP signalling commands ---- */
...
@@ -1955,37 +2005,31 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
...
@@ -1955,37 +2005,31 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
(
unsigned
long
)
&
efs
);
(
unsigned
long
)
&
efs
);
}
}
static
void
l2cap_ack_timeout
(
unsigned
long
arg
)
static
void
l2cap_ack_timeout
(
struct
work_struct
*
work
)
{
{
struct
l2cap_chan
*
chan
=
(
void
*
)
arg
;
struct
l2cap_chan
*
chan
=
container_of
(
work
,
struct
l2cap_chan
,
ack_timer
.
work
);
bh_
lock_sock
(
chan
->
sk
);
lock_sock
(
chan
->
sk
);
l2cap_send_ack
(
chan
);
l2cap_send_ack
(
chan
);
bh_unlock
_sock
(
chan
->
sk
);
release
_sock
(
chan
->
sk
);
}
}
static
inline
void
l2cap_ertm_init
(
struct
l2cap_chan
*
chan
)
static
inline
void
l2cap_ertm_init
(
struct
l2cap_chan
*
chan
)
{
{
struct
sock
*
sk
=
chan
->
sk
;
chan
->
expected_ack_seq
=
0
;
chan
->
expected_ack_seq
=
0
;
chan
->
unacked_frames
=
0
;
chan
->
unacked_frames
=
0
;
chan
->
buffer_seq
=
0
;
chan
->
buffer_seq
=
0
;
chan
->
num_acked
=
0
;
chan
->
num_acked
=
0
;
chan
->
frames_sent
=
0
;
chan
->
frames_sent
=
0
;
setup_timer
(
&
chan
->
retrans_timer
,
l2cap_retrans_timeout
,
INIT_DELAYED_WORK
(
&
chan
->
retrans_timer
,
l2cap_retrans_timeout
);
(
unsigned
long
)
chan
);
INIT_DELAYED_WORK
(
&
chan
->
monitor_timer
,
l2cap_monitor_timeout
);
setup_timer
(
&
chan
->
monitor_timer
,
l2cap_monitor_timeout
,
INIT_DELAYED_WORK
(
&
chan
->
ack_timer
,
l2cap_ack_timeout
);
(
unsigned
long
)
chan
);
setup_timer
(
&
chan
->
ack_timer
,
l2cap_ack_timeout
,
(
unsigned
long
)
chan
);
skb_queue_head_init
(
&
chan
->
srej_q
);
skb_queue_head_init
(
&
chan
->
srej_q
);
INIT_LIST_HEAD
(
&
chan
->
srej_l
);
INIT_LIST_HEAD
(
&
chan
->
srej_l
);
sk
->
sk_backlog_rcv
=
l2cap_ertm_data_rcv
;
}
}
static
inline
__u8
l2cap_select_mode
(
__u8
mode
,
__u16
remote_feat_mask
)
static
inline
__u8
l2cap_select_mode
(
__u8
mode
,
__u16
remote_feat_mask
)
...
@@ -2372,7 +2416,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
...
@@ -2372,7 +2416,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
void
*
ptr
=
req
->
data
;
void
*
ptr
=
req
->
data
;
int
type
,
olen
;
int
type
,
olen
;
unsigned
long
val
;
unsigned
long
val
;
struct
l2cap_conf_rfc
rfc
;
struct
l2cap_conf_rfc
rfc
=
{
.
mode
=
L2CAP_MODE_BASIC
}
;
struct
l2cap_conf_efs
efs
;
struct
l2cap_conf_efs
efs
;
BT_DBG
(
"chan %p, rsp %p, len %d, req %p"
,
chan
,
rsp
,
len
,
data
);
BT_DBG
(
"chan %p, rsp %p, len %d, req %p"
,
chan
,
rsp
,
len
,
data
);
...
@@ -2522,6 +2566,16 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
...
@@ -2522,6 +2566,16 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
}
}
}
}
/* Use sane default values in case a misbehaving remote device
* did not send an RFC option.
*/
rfc
.
mode
=
chan
->
mode
;
rfc
.
retrans_timeout
=
cpu_to_le16
(
L2CAP_DEFAULT_RETRANS_TO
);
rfc
.
monitor_timeout
=
cpu_to_le16
(
L2CAP_DEFAULT_MONITOR_TO
);
rfc
.
max_pdu_size
=
cpu_to_le16
(
chan
->
imtu
);
BT_ERR
(
"Expected RFC option was not found, using defaults"
);
done:
done:
switch
(
rfc
.
mode
)
{
switch
(
rfc
.
mode
)
{
case
L2CAP_MODE_ERTM
:
case
L2CAP_MODE_ERTM
:
...
@@ -2543,7 +2597,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
...
@@ -2543,7 +2597,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
if
((
conn
->
info_state
&
L2CAP_INFO_FEAT_MASK_REQ_SENT
)
&&
if
((
conn
->
info_state
&
L2CAP_INFO_FEAT_MASK_REQ_SENT
)
&&
cmd
->
ident
==
conn
->
info_ident
)
{
cmd
->
ident
==
conn
->
info_ident
)
{
del_timer
(
&
conn
->
info_timer
);
cancel_delayed_work_sync
(
&
conn
->
info_work
);
conn
->
info_state
|=
L2CAP_INFO_FEAT_MASK_REQ_DONE
;
conn
->
info_state
|=
L2CAP_INFO_FEAT_MASK_REQ_DONE
;
conn
->
info_ident
=
0
;
conn
->
info_ident
=
0
;
...
@@ -2576,7 +2630,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
...
@@ -2576,7 +2630,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
parent
=
pchan
->
sk
;
parent
=
pchan
->
sk
;
bh_
lock_sock
(
parent
);
lock_sock
(
parent
);
/* Check if the ACL is secure enough (if not SDP) */
/* Check if the ACL is secure enough (if not SDP) */
if
(
psm
!=
cpu_to_le16
(
0x0001
)
&&
if
(
psm
!=
cpu_to_le16
(
0x0001
)
&&
...
@@ -2600,11 +2654,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
...
@@ -2600,11 +2654,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
sk
=
chan
->
sk
;
sk
=
chan
->
sk
;
write_lock_bh
(
&
conn
->
chan_lock
);
/* Check if we already have channel with that dcid */
/* Check if we already have channel with that dcid */
if
(
__l2cap_get_chan_by_dcid
(
conn
,
scid
))
{
if
(
__l2cap_get_chan_by_dcid
(
conn
,
scid
))
{
write_unlock_bh
(
&
conn
->
chan_lock
);
sock_set_flag
(
sk
,
SOCK_ZAPPED
);
sock_set_flag
(
sk
,
SOCK_ZAPPED
);
chan
->
ops
->
close
(
chan
->
data
);
chan
->
ops
->
close
(
chan
->
data
);
goto
response
;
goto
response
;
...
@@ -2619,7 +2670,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
...
@@ -2619,7 +2670,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
bt_accept_enqueue
(
parent
,
sk
);
bt_accept_enqueue
(
parent
,
sk
);
__
l2cap_chan_add
(
conn
,
chan
);
l2cap_chan_add
(
conn
,
chan
);
dcid
=
chan
->
scid
;
dcid
=
chan
->
scid
;
...
@@ -2650,10 +2701,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
...
@@ -2650,10 +2701,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
status
=
L2CAP_CS_NO_INFO
;
status
=
L2CAP_CS_NO_INFO
;
}
}
write_unlock_bh
(
&
conn
->
chan_lock
);
response:
response:
bh_unlock
_sock
(
parent
);
release
_sock
(
parent
);
sendresp:
sendresp:
rsp
.
scid
=
cpu_to_le16
(
scid
);
rsp
.
scid
=
cpu_to_le16
(
scid
);
...
@@ -2669,7 +2718,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
...
@@ -2669,7 +2718,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
conn
->
info_state
|=
L2CAP_INFO_FEAT_MASK_REQ_SENT
;
conn
->
info_state
|=
L2CAP_INFO_FEAT_MASK_REQ_SENT
;
conn
->
info_ident
=
l2cap_get_ident
(
conn
);
conn
->
info_ident
=
l2cap_get_ident
(
conn
);
mod_timer
(
&
conn
->
info_timer
,
jiffies
+
schedule_delayed_work
(
&
conn
->
info_work
,
msecs_to_jiffies
(
L2CAP_INFO_TIMEOUT
));
msecs_to_jiffies
(
L2CAP_INFO_TIMEOUT
));
l2cap_send_cmd
(
conn
,
conn
->
info_ident
,
l2cap_send_cmd
(
conn
,
conn
->
info_ident
,
...
@@ -2735,19 +2784,11 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
...
@@ -2735,19 +2784,11 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
break
;
break
;
default:
default:
/* don't delete l2cap channel if sk is owned by user */
if
(
sock_owned_by_user
(
sk
))
{
l2cap_state_change
(
chan
,
BT_DISCONN
);
__clear_chan_timer
(
chan
);
__set_chan_timer
(
chan
,
L2CAP_DISC_TIMEOUT
);
break
;
}
l2cap_chan_del
(
chan
,
ECONNREFUSED
);
l2cap_chan_del
(
chan
,
ECONNREFUSED
);
break
;
break
;
}
}
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
return
0
;
return
0
;
}
}
...
@@ -2869,7 +2910,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
...
@@ -2869,7 +2910,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
}
}
unlock:
unlock:
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
return
0
;
return
0
;
}
}
...
@@ -2976,7 +3017,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
...
@@ -2976,7 +3017,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
}
}
done:
done:
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
return
0
;
return
0
;
}
}
...
@@ -3005,17 +3046,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
...
@@ -3005,17 +3046,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
sk
->
sk_shutdown
=
SHUTDOWN_MASK
;
sk
->
sk_shutdown
=
SHUTDOWN_MASK
;
/* don't delete l2cap channel if sk is owned by user */
if
(
sock_owned_by_user
(
sk
))
{
l2cap_state_change
(
chan
,
BT_DISCONN
);
__clear_chan_timer
(
chan
);
__set_chan_timer
(
chan
,
L2CAP_DISC_TIMEOUT
);
bh_unlock_sock
(
sk
);
return
0
;
}
l2cap_chan_del
(
chan
,
ECONNRESET
);
l2cap_chan_del
(
chan
,
ECONNRESET
);
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
chan
->
ops
->
close
(
chan
->
data
);
chan
->
ops
->
close
(
chan
->
data
);
return
0
;
return
0
;
...
@@ -3039,17 +3071,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
...
@@ -3039,17 +3071,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
sk
=
chan
->
sk
;
sk
=
chan
->
sk
;
/* don't delete l2cap channel if sk is owned by user */
if
(
sock_owned_by_user
(
sk
))
{
l2cap_state_change
(
chan
,
BT_DISCONN
);
__clear_chan_timer
(
chan
);
__set_chan_timer
(
chan
,
L2CAP_DISC_TIMEOUT
);
bh_unlock_sock
(
sk
);
return
0
;
}
l2cap_chan_del
(
chan
,
0
);
l2cap_chan_del
(
chan
,
0
);
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
chan
->
ops
->
close
(
chan
->
data
);
chan
->
ops
->
close
(
chan
->
data
);
return
0
;
return
0
;
...
@@ -3120,7 +3143,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
...
@@ -3120,7 +3143,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
conn
->
info_state
&
L2CAP_INFO_FEAT_MASK_REQ_DONE
)
conn
->
info_state
&
L2CAP_INFO_FEAT_MASK_REQ_DONE
)
return
0
;
return
0
;
del_timer
(
&
conn
->
info_timer
);
cancel_delayed_work_sync
(
&
conn
->
info_work
);
if
(
result
!=
L2CAP_IR_SUCCESS
)
{
if
(
result
!=
L2CAP_IR_SUCCESS
)
{
conn
->
info_state
|=
L2CAP_INFO_FEAT_MASK_REQ_DONE
;
conn
->
info_state
|=
L2CAP_INFO_FEAT_MASK_REQ_DONE
;
...
@@ -4237,12 +4260,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
...
@@ -4237,12 +4260,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
break
;
break
;
case
L2CAP_MODE_ERTM
:
case
L2CAP_MODE_ERTM
:
if
(
!
sock_owned_by_user
(
sk
))
{
l2cap_ertm_data_rcv
(
sk
,
skb
);
l2cap_ertm_data_rcv
(
sk
,
skb
);
}
else
{
if
(
sk_add_backlog
(
sk
,
skb
))
goto
drop
;
}
goto
done
;
goto
done
;
...
@@ -4292,7 +4310,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
...
@@ -4292,7 +4310,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
done:
done:
if
(
sk
)
if
(
sk
)
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
return
0
;
return
0
;
}
}
...
@@ -4308,7 +4326,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
...
@@ -4308,7 +4326,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
sk
=
chan
->
sk
;
sk
=
chan
->
sk
;
bh_
lock_sock
(
sk
);
lock_sock
(
sk
);
BT_DBG
(
"sk %p, len %d"
,
sk
,
skb
->
len
);
BT_DBG
(
"sk %p, len %d"
,
sk
,
skb
->
len
);
...
@@ -4326,7 +4344,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
...
@@ -4326,7 +4344,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
done:
done:
if
(
sk
)
if
(
sk
)
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
return
0
;
return
0
;
}
}
...
@@ -4341,7 +4359,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct
...
@@ -4341,7 +4359,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct
sk
=
chan
->
sk
;
sk
=
chan
->
sk
;
bh_
lock_sock
(
sk
);
lock_sock
(
sk
);
BT_DBG
(
"sk %p, len %d"
,
sk
,
skb
->
len
);
BT_DBG
(
"sk %p, len %d"
,
sk
,
skb
->
len
);
...
@@ -4359,7 +4377,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct
...
@@ -4359,7 +4377,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct
done:
done:
if
(
sk
)
if
(
sk
)
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
return
0
;
return
0
;
}
}
...
@@ -4518,9 +4536,9 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
...
@@ -4518,9 +4536,9 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
del_timer
(
&
conn
->
security_timer
);
del_timer
(
&
conn
->
security_timer
);
}
}
r
ead_lock
(
&
conn
->
chan_lock
);
r
cu_read_lock
(
);
list_for_each_entry
(
chan
,
&
conn
->
chan_l
,
list
)
{
list_for_each_entry
_rcu
(
chan
,
&
conn
->
chan_l
,
list
)
{
struct
sock
*
sk
=
chan
->
sk
;
struct
sock
*
sk
=
chan
->
sk
;
bh_lock_sock
(
sk
);
bh_lock_sock
(
sk
);
...
@@ -4598,7 +4616,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
...
@@ -4598,7 +4616,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
bh_unlock_sock
(
sk
);
bh_unlock_sock
(
sk
);
}
}
r
ead_unlock
(
&
conn
->
chan_lock
);
r
cu_read_unlock
(
);
return
0
;
return
0
;
}
}
...
@@ -4664,11 +4682,11 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
...
@@ -4664,11 +4682,11 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
BT_ERR
(
"Frame exceeding recv MTU (len %d, "
BT_ERR
(
"Frame exceeding recv MTU (len %d, "
"MTU %d)"
,
len
,
"MTU %d)"
,
len
,
chan
->
imtu
);
chan
->
imtu
);
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
l2cap_conn_unreliable
(
conn
,
ECOMM
);
l2cap_conn_unreliable
(
conn
,
ECOMM
);
goto
drop
;
goto
drop
;
}
}
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
}
}
/* Allocate skb for the complete frame (with header) */
/* Allocate skb for the complete frame (with header) */
...
...
net/bluetooth/l2cap_sock.c
View file @
9662cbc7
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
Copyright (C) 2000-2001 Qualcomm Incorporated
Copyright (C) 2000-2001 Qualcomm Incorporated
Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Copyright (C) 2010 Google Inc.
Copyright (C) 2010 Google Inc.
Copyright (C) 2011 ProFUSION Embedded Systems
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
...
@@ -122,69 +123,14 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
...
@@ -122,69 +123,14 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
if
(
la
.
l2_cid
&&
la
.
l2_psm
)
if
(
la
.
l2_cid
&&
la
.
l2_psm
)
return
-
EINVAL
;
return
-
EINVAL
;
lock_sock
(
sk
);
err
=
l2cap_chan_connect
(
chan
,
la
.
l2_psm
,
la
.
l2_cid
,
&
la
.
l2_bdaddr
);
if
(
chan
->
chan_type
==
L2CAP_CHAN_CONN_ORIENTED
&&
!
(
la
.
l2_psm
||
la
.
l2_cid
))
{
err
=
-
EINVAL
;
goto
done
;
}
switch
(
chan
->
mode
)
{
case
L2CAP_MODE_BASIC
:
break
;
case
L2CAP_MODE_ERTM
:
case
L2CAP_MODE_STREAMING
:
if
(
!
disable_ertm
)
break
;
/* fall through */
default:
err
=
-
ENOTSUPP
;
goto
done
;
}
switch
(
sk
->
sk_state
)
{
case
BT_CONNECT
:
case
BT_CONNECT2
:
case
BT_CONFIG
:
/* Already connecting */
goto
wait
;
case
BT_CONNECTED
:
/* Already connected */
err
=
-
EISCONN
;
goto
done
;
case
BT_OPEN
:
case
BT_BOUND
:
/* Can connect */
break
;
default:
err
=
-
EBADFD
;
goto
done
;
}
/* PSM must be odd and lsb of upper byte must be 0 */
if
((
__le16_to_cpu
(
la
.
l2_psm
)
&
0x0101
)
!=
0x0001
&&
!
la
.
l2_cid
&&
chan
->
chan_type
!=
L2CAP_CHAN_RAW
)
{
err
=
-
EINVAL
;
goto
done
;
}
/* Set destination address and psm */
bacpy
(
&
bt_sk
(
sk
)
->
dst
,
&
la
.
l2_bdaddr
);
chan
->
psm
=
la
.
l2_psm
;
chan
->
dcid
=
la
.
l2_cid
;
err
=
l2cap_chan_connect
(
l2cap_pi
(
sk
)
->
chan
);
if
(
err
)
if
(
err
)
goto
done
;
goto
done
;
wait:
err
=
bt_sock_wait_state
(
sk
,
BT_CONNECTED
,
err
=
bt_sock_wait_state
(
sk
,
BT_CONNECTED
,
sock_sndtimeo
(
sk
,
flags
&
O_NONBLOCK
));
sock_sndtimeo
(
sk
,
flags
&
O_NONBLOCK
));
done:
done:
if
(
sock_owned_by_user
(
sk
))
release_sock
(
sk
);
release_sock
(
sk
);
return
err
;
return
err
;
}
}
...
...
net/bluetooth/mgmt.c
View file @
9662cbc7
...
@@ -36,6 +36,8 @@
...
@@ -36,6 +36,8 @@
#define INQUIRY_LEN_BREDR 0x08
/* TGAP(100) */
#define INQUIRY_LEN_BREDR 0x08
/* TGAP(100) */
#define SERVICE_CACHE_TIMEOUT (5 * 1000)
struct
pending_cmd
{
struct
pending_cmd
{
struct
list_head
list
;
struct
list_head
list
;
u16
opcode
;
u16
opcode
;
...
@@ -243,6 +245,262 @@ static int read_index_list(struct sock *sk)
...
@@ -243,6 +245,262 @@ static int read_index_list(struct sock *sk)
return
err
;
return
err
;
}
}
static
u32
get_supported_settings
(
struct
hci_dev
*
hdev
)
{
u32
settings
=
0
;
settings
|=
MGMT_SETTING_POWERED
;
settings
|=
MGMT_SETTING_CONNECTABLE
;
settings
|=
MGMT_SETTING_FAST_CONNECTABLE
;
settings
|=
MGMT_SETTING_DISCOVERABLE
;
settings
|=
MGMT_SETTING_PAIRABLE
;
if
(
hdev
->
features
[
6
]
&
LMP_SIMPLE_PAIR
)
settings
|=
MGMT_SETTING_SSP
;
if
(
!
(
hdev
->
features
[
4
]
&
LMP_NO_BREDR
))
{
settings
|=
MGMT_SETTING_BREDR
;
settings
|=
MGMT_SETTING_LINK_SECURITY
;
}
if
(
hdev
->
features
[
4
]
&
LMP_LE
)
settings
|=
MGMT_SETTING_LE
;
return
settings
;
}
static
u32
get_current_settings
(
struct
hci_dev
*
hdev
)
{
u32
settings
=
0
;
if
(
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
settings
|=
MGMT_SETTING_POWERED
;
else
return
settings
;
if
(
test_bit
(
HCI_PSCAN
,
&
hdev
->
flags
))
settings
|=
MGMT_SETTING_CONNECTABLE
;
if
(
test_bit
(
HCI_ISCAN
,
&
hdev
->
flags
))
settings
|=
MGMT_SETTING_DISCOVERABLE
;
if
(
test_bit
(
HCI_PAIRABLE
,
&
hdev
->
flags
))
settings
|=
MGMT_SETTING_PAIRABLE
;
if
(
!
(
hdev
->
features
[
4
]
&
LMP_NO_BREDR
))
settings
|=
MGMT_SETTING_BREDR
;
if
(
hdev
->
extfeatures
[
0
]
&
LMP_HOST_LE
)
settings
|=
MGMT_SETTING_LE
;
if
(
test_bit
(
HCI_AUTH
,
&
hdev
->
flags
))
settings
|=
MGMT_SETTING_LINK_SECURITY
;
if
(
hdev
->
ssp_mode
>
0
)
settings
|=
MGMT_SETTING_SSP
;
return
settings
;
}
#define EIR_FLAGS 0x01
/* flags */
#define EIR_UUID16_SOME 0x02
/* 16-bit UUID, more available */
#define EIR_UUID16_ALL 0x03
/* 16-bit UUID, all listed */
#define EIR_UUID32_SOME 0x04
/* 32-bit UUID, more available */
#define EIR_UUID32_ALL 0x05
/* 32-bit UUID, all listed */
#define EIR_UUID128_SOME 0x06
/* 128-bit UUID, more available */
#define EIR_UUID128_ALL 0x07
/* 128-bit UUID, all listed */
#define EIR_NAME_SHORT 0x08
/* shortened local name */
#define EIR_NAME_COMPLETE 0x09
/* complete local name */
#define EIR_TX_POWER 0x0A
/* transmit power level */
#define EIR_DEVICE_ID 0x10
/* device ID */
#define PNP_INFO_SVCLASS_ID 0x1200
static
u8
bluetooth_base_uuid
[]
=
{
0xFB
,
0x34
,
0x9B
,
0x5F
,
0x80
,
0x00
,
0x00
,
0x80
,
0x00
,
0x10
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
};
static
u16
get_uuid16
(
u8
*
uuid128
)
{
u32
val
;
int
i
;
for
(
i
=
0
;
i
<
12
;
i
++
)
{
if
(
bluetooth_base_uuid
[
i
]
!=
uuid128
[
i
])
return
0
;
}
memcpy
(
&
val
,
&
uuid128
[
12
],
4
);
val
=
le32_to_cpu
(
val
);
if
(
val
>
0xffff
)
return
0
;
return
(
u16
)
val
;
}
static
void
create_eir
(
struct
hci_dev
*
hdev
,
u8
*
data
)
{
u8
*
ptr
=
data
;
u16
eir_len
=
0
;
u16
uuid16_list
[
HCI_MAX_EIR_LENGTH
/
sizeof
(
u16
)];
int
i
,
truncated
=
0
;
struct
bt_uuid
*
uuid
;
size_t
name_len
;
name_len
=
strlen
(
hdev
->
dev_name
);
if
(
name_len
>
0
)
{
/* EIR Data type */
if
(
name_len
>
48
)
{
name_len
=
48
;
ptr
[
1
]
=
EIR_NAME_SHORT
;
}
else
ptr
[
1
]
=
EIR_NAME_COMPLETE
;
/* EIR Data length */
ptr
[
0
]
=
name_len
+
1
;
memcpy
(
ptr
+
2
,
hdev
->
dev_name
,
name_len
);
eir_len
+=
(
name_len
+
2
);
ptr
+=
(
name_len
+
2
);
}
memset
(
uuid16_list
,
0
,
sizeof
(
uuid16_list
));
/* Group all UUID16 types */
list_for_each_entry
(
uuid
,
&
hdev
->
uuids
,
list
)
{
u16
uuid16
;
uuid16
=
get_uuid16
(
uuid
->
uuid
);
if
(
uuid16
==
0
)
return
;
if
(
uuid16
<
0x1100
)
continue
;
if
(
uuid16
==
PNP_INFO_SVCLASS_ID
)
continue
;
/* Stop if not enough space to put next UUID */
if
(
eir_len
+
2
+
sizeof
(
u16
)
>
HCI_MAX_EIR_LENGTH
)
{
truncated
=
1
;
break
;
}
/* Check for duplicates */
for
(
i
=
0
;
uuid16_list
[
i
]
!=
0
;
i
++
)
if
(
uuid16_list
[
i
]
==
uuid16
)
break
;
if
(
uuid16_list
[
i
]
==
0
)
{
uuid16_list
[
i
]
=
uuid16
;
eir_len
+=
sizeof
(
u16
);
}
}
if
(
uuid16_list
[
0
]
!=
0
)
{
u8
*
length
=
ptr
;
/* EIR Data type */
ptr
[
1
]
=
truncated
?
EIR_UUID16_SOME
:
EIR_UUID16_ALL
;
ptr
+=
2
;
eir_len
+=
2
;
for
(
i
=
0
;
uuid16_list
[
i
]
!=
0
;
i
++
)
{
*
ptr
++
=
(
uuid16_list
[
i
]
&
0x00ff
);
*
ptr
++
=
(
uuid16_list
[
i
]
&
0xff00
)
>>
8
;
}
/* EIR Data length */
*
length
=
(
i
*
sizeof
(
u16
))
+
1
;
}
}
static
int
update_eir
(
struct
hci_dev
*
hdev
)
{
struct
hci_cp_write_eir
cp
;
if
(
!
(
hdev
->
features
[
6
]
&
LMP_EXT_INQ
))
return
0
;
if
(
hdev
->
ssp_mode
==
0
)
return
0
;
if
(
test_bit
(
HCI_SERVICE_CACHE
,
&
hdev
->
flags
))
return
0
;
memset
(
&
cp
,
0
,
sizeof
(
cp
));
create_eir
(
hdev
,
cp
.
data
);
if
(
memcmp
(
cp
.
data
,
hdev
->
eir
,
sizeof
(
cp
.
data
))
==
0
)
return
0
;
memcpy
(
hdev
->
eir
,
cp
.
data
,
sizeof
(
cp
.
data
));
return
hci_send_cmd
(
hdev
,
HCI_OP_WRITE_EIR
,
sizeof
(
cp
),
&
cp
);
}
static
u8
get_service_classes
(
struct
hci_dev
*
hdev
)
{
struct
bt_uuid
*
uuid
;
u8
val
=
0
;
list_for_each_entry
(
uuid
,
&
hdev
->
uuids
,
list
)
val
|=
uuid
->
svc_hint
;
return
val
;
}
static
int
update_class
(
struct
hci_dev
*
hdev
)
{
u8
cod
[
3
];
BT_DBG
(
"%s"
,
hdev
->
name
);
if
(
test_bit
(
HCI_SERVICE_CACHE
,
&
hdev
->
flags
))
return
0
;
cod
[
0
]
=
hdev
->
minor_class
;
cod
[
1
]
=
hdev
->
major_class
;
cod
[
2
]
=
get_service_classes
(
hdev
);
if
(
memcmp
(
cod
,
hdev
->
dev_class
,
3
)
==
0
)
return
0
;
return
hci_send_cmd
(
hdev
,
HCI_OP_WRITE_CLASS_OF_DEV
,
sizeof
(
cod
),
cod
);
}
static
void
service_cache_off
(
struct
work_struct
*
work
)
{
struct
hci_dev
*
hdev
=
container_of
(
work
,
struct
hci_dev
,
service_cache
.
work
);
if
(
!
test_and_clear_bit
(
HCI_SERVICE_CACHE
,
&
hdev
->
flags
))
return
;
hci_dev_lock
(
hdev
);
update_eir
(
hdev
);
update_class
(
hdev
);
hci_dev_unlock
(
hdev
);
}
static
void
mgmt_init_hdev
(
struct
hci_dev
*
hdev
)
{
if
(
!
test_and_set_bit
(
HCI_MGMT
,
&
hdev
->
flags
))
INIT_DELAYED_WORK
(
&
hdev
->
service_cache
,
service_cache_off
);
if
(
!
test_and_set_bit
(
HCI_SERVICE_CACHE
,
&
hdev
->
flags
))
schedule_delayed_work
(
&
hdev
->
service_cache
,
msecs_to_jiffies
(
SERVICE_CACHE_TIMEOUT
));
}
static
int
read_controller_info
(
struct
sock
*
sk
,
u16
index
)
static
int
read_controller_info
(
struct
sock
*
sk
,
u16
index
)
{
{
struct
mgmt_rp_read_info
rp
;
struct
mgmt_rp_read_info
rp
;
...
@@ -258,36 +516,27 @@ static int read_controller_info(struct sock *sk, u16 index)
...
@@ -258,36 +516,27 @@ static int read_controller_info(struct sock *sk, u16 index)
if
(
test_and_clear_bit
(
HCI_AUTO_OFF
,
&
hdev
->
flags
))
if
(
test_and_clear_bit
(
HCI_AUTO_OFF
,
&
hdev
->
flags
))
cancel_delayed_work_sync
(
&
hdev
->
power_off
);
cancel_delayed_work_sync
(
&
hdev
->
power_off
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
set_bit
(
HCI_MGMT
,
&
hdev
->
flags
);
if
(
test_and_clear_bit
(
HCI_PI_MGMT_INIT
,
&
hci_pi
(
sk
)
->
flags
))
mgmt_init_hdev
(
hdev
);
memset
(
&
rp
,
0
,
sizeof
(
rp
));
memset
(
&
rp
,
0
,
sizeof
(
rp
));
rp
.
type
=
hdev
->
dev_type
;
bacpy
(
&
rp
.
bdaddr
,
&
hdev
->
bdaddr
)
;
rp
.
powered
=
test_bit
(
HCI_UP
,
&
hdev
->
flags
);
rp
.
version
=
hdev
->
hci_ver
;
rp
.
connectable
=
test_bit
(
HCI_PSCAN
,
&
hdev
->
flags
);
rp
.
discoverable
=
test_bit
(
HCI_ISCAN
,
&
hdev
->
flags
);
rp
.
pairable
=
test_bit
(
HCI_PSCAN
,
&
hdev
->
flags
);
if
(
test_bit
(
HCI_AUTH
,
&
hdev
->
flags
))
put_unaligned_le16
(
hdev
->
manufacturer
,
&
rp
.
manufacturer
);
rp
.
sec_mode
=
3
;
else
if
(
hdev
->
ssp_mode
>
0
)
rp
.
supported_settings
=
cpu_to_le32
(
get_supported_settings
(
hdev
));
rp
.
sec_mode
=
4
;
rp
.
current_settings
=
cpu_to_le32
(
get_current_settings
(
hdev
));
else
rp
.
sec_mode
=
2
;
bacpy
(
&
rp
.
bdaddr
,
&
hdev
->
bdaddr
);
memcpy
(
rp
.
features
,
hdev
->
features
,
8
);
memcpy
(
rp
.
dev_class
,
hdev
->
dev_class
,
3
);
memcpy
(
rp
.
dev_class
,
hdev
->
dev_class
,
3
);
put_unaligned_le16
(
hdev
->
manufacturer
,
&
rp
.
manufacturer
);
rp
.
hci_ver
=
hdev
->
hci_ver
;
put_unaligned_le16
(
hdev
->
hci_rev
,
&
rp
.
hci_rev
);
memcpy
(
rp
.
name
,
hdev
->
dev_name
,
sizeof
(
hdev
->
dev_name
));
memcpy
(
rp
.
name
,
hdev
->
dev_name
,
sizeof
(
hdev
->
dev_name
));
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
cmd_complete
(
sk
,
index
,
MGMT_OP_READ_INFO
,
&
rp
,
sizeof
(
rp
));
return
cmd_complete
(
sk
,
index
,
MGMT_OP_READ_INFO
,
&
rp
,
sizeof
(
rp
));
...
@@ -366,13 +615,11 @@ static void mgmt_pending_remove(struct pending_cmd *cmd)
...
@@ -366,13 +615,11 @@ static void mgmt_pending_remove(struct pending_cmd *cmd)
mgmt_pending_free
(
cmd
);
mgmt_pending_free
(
cmd
);
}
}
static
int
send_
mode_rsp
(
struct
sock
*
sk
,
u16
opcode
,
u16
index
,
u8
val
)
static
int
send_
settings_rsp
(
struct
sock
*
sk
,
u16
opcode
,
struct
hci_dev
*
hdev
)
{
{
struct
mgmt_mode
rp
;
__le32
settings
=
cpu_to_le32
(
get_current_settings
(
hdev
));
rp
.
val
=
val
;
return
cmd_complete
(
sk
,
index
,
opcode
,
&
rp
,
sizeof
(
rp
));
return
cmd_complete
(
sk
,
hdev
->
id
,
opcode
,
&
settings
,
sizeof
(
settings
));
}
}
static
int
set_powered
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
)
static
int
set_powered
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
)
...
@@ -395,11 +642,11 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
...
@@ -395,11 +642,11 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_POWERED
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_POWERED
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
up
=
test_bit
(
HCI_UP
,
&
hdev
->
flags
);
up
=
test_bit
(
HCI_UP
,
&
hdev
->
flags
);
if
((
cp
->
val
&&
up
)
||
(
!
cp
->
val
&&
!
up
))
{
if
((
cp
->
val
&&
up
)
||
(
!
cp
->
val
&&
!
up
))
{
err
=
send_
mode_rsp
(
sk
,
index
,
MGMT_OP_SET_POWERED
,
cp
->
val
);
err
=
send_
settings_rsp
(
sk
,
MGMT_OP_SET_POWERED
,
hdev
);
goto
failed
;
goto
failed
;
}
}
...
@@ -416,14 +663,14 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
...
@@ -416,14 +663,14 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
}
}
if
(
cp
->
val
)
if
(
cp
->
val
)
queue_work
(
hdev
->
workqueue
,
&
hdev
->
power_on
);
schedule_work
(
&
hdev
->
power_on
);
else
else
queue_work
(
hdev
->
workqueue
,
&
hdev
->
power_off
.
work
);
schedule_work
(
&
hdev
->
power_off
.
work
);
err
=
0
;
err
=
0
;
failed:
failed:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
}
}
...
@@ -450,7 +697,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
...
@@ -450,7 +697,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
...
@@ -467,8 +714,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
...
@@ -467,8 +714,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
if
(
cp
->
val
==
test_bit
(
HCI_ISCAN
,
&
hdev
->
flags
)
&&
if
(
cp
->
val
==
test_bit
(
HCI_ISCAN
,
&
hdev
->
flags
)
&&
test_bit
(
HCI_PSCAN
,
&
hdev
->
flags
))
{
test_bit
(
HCI_PSCAN
,
&
hdev
->
flags
))
{
err
=
send_mode_rsp
(
sk
,
index
,
MGMT_OP_SET_DISCOVERABLE
,
err
=
send_settings_rsp
(
sk
,
MGMT_OP_SET_DISCOVERABLE
,
hdev
);
cp
->
val
);
goto
failed
;
goto
failed
;
}
}
...
@@ -493,7 +739,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
...
@@ -493,7 +739,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
hdev
->
discov_timeout
=
get_unaligned_le16
(
&
cp
->
timeout
);
hdev
->
discov_timeout
=
get_unaligned_le16
(
&
cp
->
timeout
);
failed:
failed:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -521,7 +767,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
...
@@ -521,7 +767,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
...
@@ -537,8 +783,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
...
@@ -537,8 +783,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
}
}
if
(
cp
->
val
==
test_bit
(
HCI_PSCAN
,
&
hdev
->
flags
))
{
if
(
cp
->
val
==
test_bit
(
HCI_PSCAN
,
&
hdev
->
flags
))
{
err
=
send_mode_rsp
(
sk
,
index
,
MGMT_OP_SET_CONNECTABLE
,
err
=
send_settings_rsp
(
sk
,
MGMT_OP_SET_CONNECTABLE
,
hdev
);
cp
->
val
);
goto
failed
;
goto
failed
;
}
}
...
@@ -558,7 +803,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
...
@@ -558,7 +803,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove
(
cmd
);
mgmt_pending_remove
(
cmd
);
failed:
failed:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -596,8 +841,9 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
...
@@ -596,8 +841,9 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
static
int
set_pairable
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
static
int
set_pairable
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
)
u16
len
)
{
{
struct
mgmt_mode
*
cp
,
ev
;
struct
mgmt_mode
*
cp
;
struct
hci_dev
*
hdev
;
struct
hci_dev
*
hdev
;
__le32
ev
;
int
err
;
int
err
;
cp
=
(
void
*
)
data
;
cp
=
(
void
*
)
data
;
...
@@ -613,201 +859,28 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
...
@@ -613,201 +859,28 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_PAIRABLE
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_PAIRABLE
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
if
(
cp
->
val
)
if
(
cp
->
val
)
set_bit
(
HCI_PAIRABLE
,
&
hdev
->
flags
);
set_bit
(
HCI_PAIRABLE
,
&
hdev
->
flags
);
else
else
clear_bit
(
HCI_PAIRABLE
,
&
hdev
->
flags
);
clear_bit
(
HCI_PAIRABLE
,
&
hdev
->
flags
);
err
=
send_
mode_rsp
(
sk
,
MGMT_OP_SET_PAIRABLE
,
index
,
cp
->
val
);
err
=
send_
settings_rsp
(
sk
,
MGMT_OP_SET_PAIRABLE
,
hdev
);
if
(
err
<
0
)
if
(
err
<
0
)
goto
failed
;
goto
failed
;
ev
.
val
=
cp
->
val
;
ev
=
cpu_to_le32
(
get_current_settings
(
hdev
))
;
err
=
mgmt_event
(
MGMT_EV_
PAIRABLE
,
hdev
,
&
ev
,
sizeof
(
ev
),
sk
);
err
=
mgmt_event
(
MGMT_EV_
NEW_SETTINGS
,
hdev
,
&
ev
,
sizeof
(
ev
),
sk
);
failed:
failed:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
}
}
#define EIR_FLAGS 0x01
/* flags */
#define EIR_UUID16_SOME 0x02
/* 16-bit UUID, more available */
#define EIR_UUID16_ALL 0x03
/* 16-bit UUID, all listed */
#define EIR_UUID32_SOME 0x04
/* 32-bit UUID, more available */
#define EIR_UUID32_ALL 0x05
/* 32-bit UUID, all listed */
#define EIR_UUID128_SOME 0x06
/* 128-bit UUID, more available */
#define EIR_UUID128_ALL 0x07
/* 128-bit UUID, all listed */
#define EIR_NAME_SHORT 0x08
/* shortened local name */
#define EIR_NAME_COMPLETE 0x09
/* complete local name */
#define EIR_TX_POWER 0x0A
/* transmit power level */
#define EIR_DEVICE_ID 0x10
/* device ID */
#define PNP_INFO_SVCLASS_ID 0x1200
static
u8
bluetooth_base_uuid
[]
=
{
0xFB
,
0x34
,
0x9B
,
0x5F
,
0x80
,
0x00
,
0x00
,
0x80
,
0x00
,
0x10
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
};
static
u16
get_uuid16
(
u8
*
uuid128
)
{
u32
val
;
int
i
;
for
(
i
=
0
;
i
<
12
;
i
++
)
{
if
(
bluetooth_base_uuid
[
i
]
!=
uuid128
[
i
])
return
0
;
}
memcpy
(
&
val
,
&
uuid128
[
12
],
4
);
val
=
le32_to_cpu
(
val
);
if
(
val
>
0xffff
)
return
0
;
return
(
u16
)
val
;
}
static
void
create_eir
(
struct
hci_dev
*
hdev
,
u8
*
data
)
{
u8
*
ptr
=
data
;
u16
eir_len
=
0
;
u16
uuid16_list
[
HCI_MAX_EIR_LENGTH
/
sizeof
(
u16
)];
int
i
,
truncated
=
0
;
struct
bt_uuid
*
uuid
;
size_t
name_len
;
name_len
=
strlen
(
hdev
->
dev_name
);
if
(
name_len
>
0
)
{
/* EIR Data type */
if
(
name_len
>
48
)
{
name_len
=
48
;
ptr
[
1
]
=
EIR_NAME_SHORT
;
}
else
ptr
[
1
]
=
EIR_NAME_COMPLETE
;
/* EIR Data length */
ptr
[
0
]
=
name_len
+
1
;
memcpy
(
ptr
+
2
,
hdev
->
dev_name
,
name_len
);
eir_len
+=
(
name_len
+
2
);
ptr
+=
(
name_len
+
2
);
}
memset
(
uuid16_list
,
0
,
sizeof
(
uuid16_list
));
/* Group all UUID16 types */
list_for_each_entry
(
uuid
,
&
hdev
->
uuids
,
list
)
{
u16
uuid16
;
uuid16
=
get_uuid16
(
uuid
->
uuid
);
if
(
uuid16
==
0
)
return
;
if
(
uuid16
<
0x1100
)
continue
;
if
(
uuid16
==
PNP_INFO_SVCLASS_ID
)
continue
;
/* Stop if not enough space to put next UUID */
if
(
eir_len
+
2
+
sizeof
(
u16
)
>
HCI_MAX_EIR_LENGTH
)
{
truncated
=
1
;
break
;
}
/* Check for duplicates */
for
(
i
=
0
;
uuid16_list
[
i
]
!=
0
;
i
++
)
if
(
uuid16_list
[
i
]
==
uuid16
)
break
;
if
(
uuid16_list
[
i
]
==
0
)
{
uuid16_list
[
i
]
=
uuid16
;
eir_len
+=
sizeof
(
u16
);
}
}
if
(
uuid16_list
[
0
]
!=
0
)
{
u8
*
length
=
ptr
;
/* EIR Data type */
ptr
[
1
]
=
truncated
?
EIR_UUID16_SOME
:
EIR_UUID16_ALL
;
ptr
+=
2
;
eir_len
+=
2
;
for
(
i
=
0
;
uuid16_list
[
i
]
!=
0
;
i
++
)
{
*
ptr
++
=
(
uuid16_list
[
i
]
&
0x00ff
);
*
ptr
++
=
(
uuid16_list
[
i
]
&
0xff00
)
>>
8
;
}
/* EIR Data length */
*
length
=
(
i
*
sizeof
(
u16
))
+
1
;
}
}
static
int
update_eir
(
struct
hci_dev
*
hdev
)
{
struct
hci_cp_write_eir
cp
;
if
(
!
(
hdev
->
features
[
6
]
&
LMP_EXT_INQ
))
return
0
;
if
(
hdev
->
ssp_mode
==
0
)
return
0
;
if
(
test_bit
(
HCI_SERVICE_CACHE
,
&
hdev
->
flags
))
return
0
;
memset
(
&
cp
,
0
,
sizeof
(
cp
));
create_eir
(
hdev
,
cp
.
data
);
if
(
memcmp
(
cp
.
data
,
hdev
->
eir
,
sizeof
(
cp
.
data
))
==
0
)
return
0
;
memcpy
(
hdev
->
eir
,
cp
.
data
,
sizeof
(
cp
.
data
));
return
hci_send_cmd
(
hdev
,
HCI_OP_WRITE_EIR
,
sizeof
(
cp
),
&
cp
);
}
static
u8
get_service_classes
(
struct
hci_dev
*
hdev
)
{
struct
bt_uuid
*
uuid
;
u8
val
=
0
;
list_for_each_entry
(
uuid
,
&
hdev
->
uuids
,
list
)
val
|=
uuid
->
svc_hint
;
return
val
;
}
static
int
update_class
(
struct
hci_dev
*
hdev
)
{
u8
cod
[
3
];
BT_DBG
(
"%s"
,
hdev
->
name
);
if
(
test_bit
(
HCI_SERVICE_CACHE
,
&
hdev
->
flags
))
return
0
;
cod
[
0
]
=
hdev
->
minor_class
;
cod
[
1
]
=
hdev
->
major_class
;
cod
[
2
]
=
get_service_classes
(
hdev
);
if
(
memcmp
(
cod
,
hdev
->
dev_class
,
3
)
==
0
)
return
0
;
return
hci_send_cmd
(
hdev
,
HCI_OP_WRITE_CLASS_OF_DEV
,
sizeof
(
cod
),
cod
);
}
static
int
add_uuid
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
)
static
int
add_uuid
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
)
{
{
struct
mgmt_cp_add_uuid
*
cp
;
struct
mgmt_cp_add_uuid
*
cp
;
...
@@ -828,7 +901,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
...
@@ -828,7 +901,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
return
cmd_status
(
sk
,
index
,
MGMT_OP_ADD_UUID
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_ADD_UUID
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
uuid
=
kmalloc
(
sizeof
(
*
uuid
),
GFP_ATOMIC
);
uuid
=
kmalloc
(
sizeof
(
*
uuid
),
GFP_ATOMIC
);
if
(
!
uuid
)
{
if
(
!
uuid
)
{
...
@@ -852,7 +925,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
...
@@ -852,7 +925,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_ADD_UUID
,
NULL
,
0
);
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_ADD_UUID
,
NULL
,
0
);
failed:
failed:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -879,7 +952,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
...
@@ -879,7 +952,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_UUID
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_UUID
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
if
(
memcmp
(
cp
->
uuid
,
bt_uuid_any
,
16
)
==
0
)
{
if
(
memcmp
(
cp
->
uuid
,
bt_uuid_any
,
16
)
==
0
)
{
err
=
hci_uuids_clear
(
hdev
);
err
=
hci_uuids_clear
(
hdev
);
...
@@ -915,7 +988,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
...
@@ -915,7 +988,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_REMOVE_UUID
,
NULL
,
0
);
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_REMOVE_UUID
,
NULL
,
0
);
unlock:
unlock:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -941,62 +1014,24 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
...
@@ -941,62 +1014,24 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DEV_CLASS
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_DEV_CLASS
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
hdev
->
major_class
=
cp
->
major
;
hdev
->
major_class
=
cp
->
major
;
hdev
->
minor_class
=
cp
->
minor
;
hdev
->
minor_class
=
cp
->
minor
;
err
=
update_class
(
hdev
);
if
(
test_and_clear_bit
(
HCI_SERVICE_CACHE
,
&
hdev
->
flags
))
{
hci_dev_unlock
(
hdev
);
if
(
err
==
0
)
cancel_delayed_work_sync
(
&
hdev
->
service_cache
);
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_SET_DEV_CLASS
,
NULL
,
0
);
hci_dev_lock
(
hdev
);
update_eir
(
hdev
);
hci_dev_unlock_bh
(
hdev
);
}
hci_dev_put
(
hdev
);
return
err
;
}
static
int
set_service_cache
(
struct
sock
*
sk
,
u16
index
,
unsigned
char
*
data
,
u16
len
)
{
struct
hci_dev
*
hdev
;
struct
mgmt_cp_set_service_cache
*
cp
;
int
err
;
cp
=
(
void
*
)
data
;
if
(
len
!=
sizeof
(
*
cp
))
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_SERVICE_CACHE
,
MGMT_STATUS_INVALID_PARAMS
);
hdev
=
hci_dev_get
(
index
);
if
(
!
hdev
)
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_SERVICE_CACHE
,
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock_bh
(
hdev
);
BT_DBG
(
"hci%u enable %d"
,
index
,
cp
->
enable
);
if
(
cp
->
enable
)
{
set_bit
(
HCI_SERVICE_CACHE
,
&
hdev
->
flags
);
err
=
0
;
}
else
{
clear_bit
(
HCI_SERVICE_CACHE
,
&
hdev
->
flags
);
err
=
update_class
(
hdev
);
err
=
update_class
(
hdev
);
if
(
err
==
0
)
err
=
update_eir
(
hdev
);
}
if
(
err
==
0
)
if
(
err
==
0
)
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_SET_SERVICE_CACHE
,
NULL
,
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_SET_DEV_CLASS
,
NULL
,
0
);
0
);
else
cmd_status
(
sk
,
index
,
MGMT_OP_SET_SERVICE_CACHE
,
-
err
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -1035,7 +1070,7 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1035,7 +1070,7 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
BT_DBG
(
"hci%u debug_keys %u key_count %u"
,
index
,
cp
->
debug_keys
,
BT_DBG
(
"hci%u debug_keys %u key_count %u"
,
index
,
cp
->
debug_keys
,
key_count
);
key_count
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
hci_link_keys_clear
(
hdev
);
hci_link_keys_clear
(
hdev
);
...
@@ -1055,7 +1090,7 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1055,7 +1090,7 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
cmd_complete
(
sk
,
index
,
MGMT_OP_LOAD_LINK_KEYS
,
NULL
,
0
);
cmd_complete
(
sk
,
index
,
MGMT_OP_LOAD_LINK_KEYS
,
NULL
,
0
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
0
;
return
0
;
...
@@ -1083,7 +1118,7 @@ static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1083,7 +1118,7 @@ static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_KEYS
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_KEYS
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
memset
(
&
rp
,
0
,
sizeof
(
rp
));
memset
(
&
rp
,
0
,
sizeof
(
rp
));
bacpy
(
&
rp
.
bdaddr
,
&
cp
->
bdaddr
);
bacpy
(
&
rp
.
bdaddr
,
&
cp
->
bdaddr
);
...
@@ -1124,7 +1159,7 @@ static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1124,7 +1159,7 @@ static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
if
(
err
<
0
)
if
(
err
<
0
)
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_REMOVE_KEYS
,
&
rp
,
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_REMOVE_KEYS
,
&
rp
,
sizeof
(
rp
));
sizeof
(
rp
));
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -1152,7 +1187,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
...
@@ -1152,7 +1187,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
return
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_DISCONNECT
,
...
@@ -1190,7 +1225,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
...
@@ -1190,7 +1225,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
mgmt_pending_remove
(
cmd
);
mgmt_pending_remove
(
cmd
);
failed:
failed:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -1232,7 +1267,7 @@ static int get_connections(struct sock *sk, u16 index)
...
@@ -1232,7 +1267,7 @@ static int get_connections(struct sock *sk, u16 index)
return
cmd_status
(
sk
,
index
,
MGMT_OP_GET_CONNECTIONS
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_GET_CONNECTIONS
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
count
=
0
;
count
=
0
;
list_for_each
(
p
,
&
hdev
->
conn_hash
.
list
)
{
list_for_each
(
p
,
&
hdev
->
conn_hash
.
list
)
{
...
@@ -1264,7 +1299,7 @@ static int get_connections(struct sock *sk, u16 index)
...
@@ -1264,7 +1299,7 @@ static int get_connections(struct sock *sk, u16 index)
unlock:
unlock:
kfree
(
rp
);
kfree
(
rp
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
}
}
...
@@ -1312,7 +1347,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1312,7 +1347,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_REPLY
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_REPLY
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_REPLY
,
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_REPLY
,
...
@@ -1355,7 +1390,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1355,7 +1390,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove
(
cmd
);
mgmt_pending_remove
(
cmd
);
failed:
failed:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -1381,7 +1416,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1381,7 +1416,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_NEG_REPLY
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_NEG_REPLY
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_NEG_REPLY
,
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_PIN_CODE_NEG_REPLY
,
...
@@ -1392,7 +1427,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1392,7 +1427,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
err
=
send_pin_code_neg_reply
(
sk
,
index
,
hdev
,
cp
);
err
=
send_pin_code_neg_reply
(
sk
,
index
,
hdev
,
cp
);
failed:
failed:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -1417,14 +1452,14 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1417,14 +1452,14 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_IO_CAPABILITY
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_IO_CAPABILITY
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
hdev
->
io_capability
=
cp
->
io_capability
;
hdev
->
io_capability
=
cp
->
io_capability
;
BT_DBG
(
"%s IO capability set to 0x%02x"
,
hdev
->
name
,
BT_DBG
(
"%s IO capability set to 0x%02x"
,
hdev
->
name
,
hdev
->
io_capability
);
hdev
->
io_capability
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
cmd_complete
(
sk
,
index
,
MGMT_OP_SET_IO_CAPABILITY
,
NULL
,
0
);
return
cmd_complete
(
sk
,
index
,
MGMT_OP_SET_IO_CAPABILITY
,
NULL
,
0
);
...
@@ -1505,7 +1540,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
...
@@ -1505,7 +1540,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
return
cmd_status
(
sk
,
index
,
MGMT_OP_PAIR_DEVICE
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_PAIR_DEVICE
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
sec_level
=
BT_SECURITY_MEDIUM
;
sec_level
=
BT_SECURITY_MEDIUM
;
if
(
cp
->
io_cap
==
0x03
)
if
(
cp
->
io_cap
==
0x03
)
...
@@ -1562,7 +1597,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
...
@@ -1562,7 +1597,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
err
=
0
;
err
=
0
;
unlock:
unlock:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -1581,7 +1616,7 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
...
@@ -1581,7 +1616,7 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
return
cmd_status
(
sk
,
index
,
mgmt_op
,
return
cmd_status
(
sk
,
index
,
mgmt_op
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
mgmt_op
,
MGMT_STATUS_NOT_POWERED
);
err
=
cmd_status
(
sk
,
index
,
mgmt_op
,
MGMT_STATUS_NOT_POWERED
);
...
@@ -1632,7 +1667,7 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
...
@@ -1632,7 +1667,7 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
mgmt_pending_remove
(
cmd
);
mgmt_pending_remove
(
cmd
);
done:
done:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -1656,7 +1691,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
...
@@ -1656,7 +1691,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
static
int
user_confirm_neg_reply
(
struct
sock
*
sk
,
u16
index
,
void
*
data
,
static
int
user_confirm_neg_reply
(
struct
sock
*
sk
,
u16
index
,
void
*
data
,
u16
len
)
u16
len
)
{
{
struct
mgmt_cp_user_confirm_
reply
*
cp
=
(
void
*
)
data
;
struct
mgmt_cp_user_confirm_
neg_reply
*
cp
=
data
;
BT_DBG
(
""
);
BT_DBG
(
""
);
...
@@ -1720,7 +1755,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1720,7 +1755,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_LOCAL_NAME
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_SET_LOCAL_NAME
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
cmd
=
mgmt_pending_add
(
sk
,
MGMT_OP_SET_LOCAL_NAME
,
hdev
,
data
,
len
);
cmd
=
mgmt_pending_add
(
sk
,
MGMT_OP_SET_LOCAL_NAME
,
hdev
,
data
,
len
);
if
(
!
cmd
)
{
if
(
!
cmd
)
{
...
@@ -1735,7 +1770,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1735,7 +1770,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
mgmt_pending_remove
(
cmd
);
mgmt_pending_remove
(
cmd
);
failed:
failed:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -1754,7 +1789,7 @@ static int read_local_oob_data(struct sock *sk, u16 index)
...
@@ -1754,7 +1789,7 @@ static int read_local_oob_data(struct sock *sk, u16 index)
return
cmd_status
(
sk
,
index
,
MGMT_OP_READ_LOCAL_OOB_DATA
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_READ_LOCAL_OOB_DATA
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_READ_LOCAL_OOB_DATA
,
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_READ_LOCAL_OOB_DATA
,
...
@@ -1785,7 +1820,7 @@ static int read_local_oob_data(struct sock *sk, u16 index)
...
@@ -1785,7 +1820,7 @@ static int read_local_oob_data(struct sock *sk, u16 index)
mgmt_pending_remove
(
cmd
);
mgmt_pending_remove
(
cmd
);
unlock:
unlock:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -1809,7 +1844,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1809,7 +1844,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_ADD_REMOTE_OOB_DATA
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_ADD_REMOTE_OOB_DATA
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
err
=
hci_add_remote_oob_data
(
hdev
,
&
cp
->
bdaddr
,
cp
->
hash
,
err
=
hci_add_remote_oob_data
(
hdev
,
&
cp
->
bdaddr
,
cp
->
hash
,
cp
->
randomizer
);
cp
->
randomizer
);
...
@@ -1820,7 +1855,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1820,7 +1855,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_ADD_REMOTE_OOB_DATA
,
NULL
,
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_ADD_REMOTE_OOB_DATA
,
NULL
,
0
);
0
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -1844,7 +1879,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
...
@@ -1844,7 +1879,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_REMOTE_OOB_DATA
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_REMOVE_REMOTE_OOB_DATA
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
err
=
hci_remove_remote_oob_data
(
hdev
,
&
cp
->
bdaddr
);
err
=
hci_remove_remote_oob_data
(
hdev
,
&
cp
->
bdaddr
);
if
(
err
<
0
)
if
(
err
<
0
)
...
@@ -1854,7 +1889,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
...
@@ -1854,7 +1889,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_REMOVE_REMOTE_OOB_DATA
,
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_REMOVE_REMOTE_OOB_DATA
,
NULL
,
0
);
NULL
,
0
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -1879,7 +1914,7 @@ static int start_discovery(struct sock *sk, u16 index,
...
@@ -1879,7 +1914,7 @@ static int start_discovery(struct sock *sk, u16 index,
return
cmd_status
(
sk
,
index
,
MGMT_OP_START_DISCOVERY
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_START_DISCOVERY
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
if
(
!
test_bit
(
HCI_UP
,
&
hdev
->
flags
))
{
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_START_DISCOVERY
,
err
=
cmd_status
(
sk
,
index
,
MGMT_OP_START_DISCOVERY
,
...
@@ -1898,7 +1933,7 @@ static int start_discovery(struct sock *sk, u16 index,
...
@@ -1898,7 +1933,7 @@ static int start_discovery(struct sock *sk, u16 index,
mgmt_pending_remove
(
cmd
);
mgmt_pending_remove
(
cmd
);
failed:
failed:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -1917,7 +1952,7 @@ static int stop_discovery(struct sock *sk, u16 index)
...
@@ -1917,7 +1952,7 @@ static int stop_discovery(struct sock *sk, u16 index)
return
cmd_status
(
sk
,
index
,
MGMT_OP_STOP_DISCOVERY
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_STOP_DISCOVERY
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
cmd
=
mgmt_pending_add
(
sk
,
MGMT_OP_STOP_DISCOVERY
,
hdev
,
NULL
,
0
);
cmd
=
mgmt_pending_add
(
sk
,
MGMT_OP_STOP_DISCOVERY
,
hdev
,
NULL
,
0
);
if
(
!
cmd
)
{
if
(
!
cmd
)
{
...
@@ -1930,7 +1965,7 @@ static int stop_discovery(struct sock *sk, u16 index)
...
@@ -1930,7 +1965,7 @@ static int stop_discovery(struct sock *sk, u16 index)
mgmt_pending_remove
(
cmd
);
mgmt_pending_remove
(
cmd
);
failed:
failed:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -1954,7 +1989,7 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1954,7 +1989,7 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
err
=
hci_blacklist_add
(
hdev
,
&
cp
->
bdaddr
);
err
=
hci_blacklist_add
(
hdev
,
&
cp
->
bdaddr
);
if
(
err
<
0
)
if
(
err
<
0
)
...
@@ -1964,7 +1999,7 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1964,7 +1999,7 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_BLOCK_DEVICE
,
NULL
,
0
);
NULL
,
0
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -1988,7 +2023,7 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1988,7 +2023,7 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
return
cmd_status
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
return
cmd_status
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
MGMT_STATUS_INVALID_PARAMS
);
MGMT_STATUS_INVALID_PARAMS
);
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
err
=
hci_blacklist_del
(
hdev
,
&
cp
->
bdaddr
);
err
=
hci_blacklist_del
(
hdev
,
&
cp
->
bdaddr
);
...
@@ -1999,7 +2034,7 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
...
@@ -1999,7 +2034,7 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
err
=
cmd_complete
(
sk
,
index
,
MGMT_OP_UNBLOCK_DEVICE
,
NULL
,
0
);
NULL
,
0
);
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
...
@@ -2009,7 +2044,7 @@ static int set_fast_connectable(struct sock *sk, u16 index,
...
@@ -2009,7 +2044,7 @@ static int set_fast_connectable(struct sock *sk, u16 index,
unsigned
char
*
data
,
u16
len
)
unsigned
char
*
data
,
u16
len
)
{
{
struct
hci_dev
*
hdev
;
struct
hci_dev
*
hdev
;
struct
mgmt_
cp_set_fast_connectabl
e
*
cp
=
(
void
*
)
data
;
struct
mgmt_
mod
e
*
cp
=
(
void
*
)
data
;
struct
hci_cp_write_page_scan_activity
acp
;
struct
hci_cp_write_page_scan_activity
acp
;
u8
type
;
u8
type
;
int
err
;
int
err
;
...
@@ -2027,7 +2062,7 @@ static int set_fast_connectable(struct sock *sk, u16 index,
...
@@ -2027,7 +2062,7 @@ static int set_fast_connectable(struct sock *sk, u16 index,
hci_dev_lock
(
hdev
);
hci_dev_lock
(
hdev
);
if
(
cp
->
enable
)
{
if
(
cp
->
val
)
{
type
=
PAGE_SCAN_TYPE_INTERLACED
;
type
=
PAGE_SCAN_TYPE_INTERLACED
;
acp
.
interval
=
0x0024
;
/* 22.5 msec page scan interval */
acp
.
interval
=
0x0024
;
/* 22.5 msec page scan interval */
}
else
{
}
else
{
...
@@ -2111,6 +2146,10 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
...
@@ -2111,6 +2146,10 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case
MGMT_OP_SET_CONNECTABLE
:
case
MGMT_OP_SET_CONNECTABLE
:
err
=
set_connectable
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
err
=
set_connectable
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
break
;
case
MGMT_OP_SET_FAST_CONNECTABLE
:
err
=
set_fast_connectable
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
case
MGMT_OP_SET_PAIRABLE
:
case
MGMT_OP_SET_PAIRABLE
:
err
=
set_pairable
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
err
=
set_pairable
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
break
;
...
@@ -2123,9 +2162,6 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
...
@@ -2123,9 +2162,6 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case
MGMT_OP_SET_DEV_CLASS
:
case
MGMT_OP_SET_DEV_CLASS
:
err
=
set_dev_class
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
err
=
set_dev_class
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
break
;
case
MGMT_OP_SET_SERVICE_CACHE
:
err
=
set_service_cache
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
case
MGMT_OP_LOAD_LINK_KEYS
:
case
MGMT_OP_LOAD_LINK_KEYS
:
err
=
load_link_keys
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
err
=
load_link_keys
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
break
;
...
@@ -2189,10 +2225,6 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
...
@@ -2189,10 +2225,6 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case
MGMT_OP_UNBLOCK_DEVICE
:
case
MGMT_OP_UNBLOCK_DEVICE
:
err
=
unblock_device
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
err
=
unblock_device
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
break
;
case
MGMT_OP_SET_FAST_CONNECTABLE
:
err
=
set_fast_connectable
(
sk
,
index
,
buf
+
sizeof
(
*
hdr
),
len
);
break
;
default:
default:
BT_DBG
(
"Unknown op %u"
,
opcode
);
BT_DBG
(
"Unknown op %u"
,
opcode
);
err
=
cmd_status
(
sk
,
index
,
opcode
,
err
=
cmd_status
(
sk
,
index
,
opcode
,
...
@@ -2235,17 +2267,14 @@ int mgmt_index_removed(struct hci_dev *hdev)
...
@@ -2235,17 +2267,14 @@ int mgmt_index_removed(struct hci_dev *hdev)
struct
cmd_lookup
{
struct
cmd_lookup
{
u8
val
;
u8
val
;
struct
sock
*
sk
;
struct
sock
*
sk
;
struct
hci_dev
*
hdev
;
};
};
static
void
mode
_rsp
(
struct
pending_cmd
*
cmd
,
void
*
data
)
static
void
settings
_rsp
(
struct
pending_cmd
*
cmd
,
void
*
data
)
{
{
struct
mgmt_mode
*
cp
=
cmd
->
param
;
struct
cmd_lookup
*
match
=
data
;
struct
cmd_lookup
*
match
=
data
;
if
(
cp
->
val
!=
match
->
val
)
send_settings_rsp
(
cmd
->
sk
,
cmd
->
opcode
,
match
->
hdev
);
return
;
send_mode_rsp
(
cmd
->
sk
,
cmd
->
opcode
,
cmd
->
index
,
cp
->
val
);
list_del
(
&
cmd
->
list
);
list_del
(
&
cmd
->
list
);
...
@@ -2259,20 +2288,21 @@ static void mode_rsp(struct pending_cmd *cmd, void *data)
...
@@ -2259,20 +2288,21 @@ static void mode_rsp(struct pending_cmd *cmd, void *data)
int
mgmt_powered
(
struct
hci_dev
*
hdev
,
u8
powered
)
int
mgmt_powered
(
struct
hci_dev
*
hdev
,
u8
powered
)
{
{
struct
mgmt_mode
ev
;
struct
cmd_lookup
match
=
{
powered
,
NULL
,
hdev
}
;
struct
cmd_lookup
match
=
{
powered
,
NULL
}
;
__le32
ev
;
int
ret
;
int
ret
;
mgmt_pending_foreach
(
MGMT_OP_SET_POWERED
,
hdev
,
mode
_rsp
,
&
match
);
mgmt_pending_foreach
(
MGMT_OP_SET_POWERED
,
hdev
,
settings
_rsp
,
&
match
);
if
(
!
powered
)
{
if
(
!
powered
)
{
u8
status
=
ENETDOWN
;
u8
status
=
ENETDOWN
;
mgmt_pending_foreach
(
0
,
hdev
,
cmd_status_rsp
,
&
status
);
mgmt_pending_foreach
(
0
,
hdev
,
cmd_status_rsp
,
&
status
);
}
}
ev
.
val
=
powered
;
ev
=
cpu_to_le32
(
get_current_settings
(
hdev
))
;
ret
=
mgmt_event
(
MGMT_EV_POWERED
,
hdev
,
&
ev
,
sizeof
(
ev
),
match
.
sk
);
ret
=
mgmt_event
(
MGMT_EV_NEW_SETTINGS
,
hdev
,
&
ev
,
sizeof
(
ev
),
match
.
sk
);
if
(
match
.
sk
)
if
(
match
.
sk
)
sock_put
(
match
.
sk
);
sock_put
(
match
.
sk
);
...
@@ -2282,17 +2312,16 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered)
...
@@ -2282,17 +2312,16 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered)
int
mgmt_discoverable
(
struct
hci_dev
*
hdev
,
u8
discoverable
)
int
mgmt_discoverable
(
struct
hci_dev
*
hdev
,
u8
discoverable
)
{
{
struct
mgmt_mode
ev
;
struct
cmd_lookup
match
=
{
discoverable
,
NULL
,
hdev
}
;
struct
cmd_lookup
match
=
{
discoverable
,
NULL
}
;
__le32
ev
;
int
ret
;
int
ret
;
mgmt_pending_foreach
(
MGMT_OP_SET_DISCOVERABLE
,
hdev
,
mode
_rsp
,
&
match
);
mgmt_pending_foreach
(
MGMT_OP_SET_DISCOVERABLE
,
hdev
,
settings
_rsp
,
&
match
);
ev
.
val
=
discoverable
;
ev
=
cpu_to_le32
(
get_current_settings
(
hdev
))
;
ret
=
mgmt_event
(
MGMT_EV_
DISCOVERABLE
,
hdev
,
&
ev
,
sizeof
(
ev
),
ret
=
mgmt_event
(
MGMT_EV_
NEW_SETTINGS
,
hdev
,
&
ev
,
sizeof
(
ev
),
match
.
sk
);
match
.
sk
);
if
(
match
.
sk
)
if
(
match
.
sk
)
sock_put
(
match
.
sk
);
sock_put
(
match
.
sk
);
...
@@ -2301,15 +2330,16 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
...
@@ -2301,15 +2330,16 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
int
mgmt_connectable
(
struct
hci_dev
*
hdev
,
u8
connectable
)
int
mgmt_connectable
(
struct
hci_dev
*
hdev
,
u8
connectable
)
{
{
struct
mgmt_mode
ev
;
__le32
ev
;
struct
cmd_lookup
match
=
{
connectable
,
NULL
};
struct
cmd_lookup
match
=
{
connectable
,
NULL
,
hdev
};
int
ret
;
int
ret
;
mgmt_pending_foreach
(
MGMT_OP_SET_CONNECTABLE
,
hdev
,
mode_rsp
,
&
match
);
mgmt_pending_foreach
(
MGMT_OP_SET_CONNECTABLE
,
hdev
,
settings_rsp
,
&
match
);
ev
.
val
=
connectable
;
ev
=
cpu_to_le32
(
get_current_settings
(
hdev
))
;
ret
=
mgmt_event
(
MGMT_EV_
CONNECTABLE
,
hdev
,
&
ev
,
sizeof
(
ev
),
match
.
sk
);
ret
=
mgmt_event
(
MGMT_EV_
NEW_SETTINGS
,
hdev
,
&
ev
,
sizeof
(
ev
),
match
.
sk
);
if
(
match
.
sk
)
if
(
match
.
sk
)
sock_put
(
match
.
sk
);
sock_put
(
match
.
sk
);
...
...
net/bluetooth/rfcomm/core.c
View file @
9662cbc7
...
@@ -1162,6 +1162,7 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
...
@@ -1162,6 +1162,7 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
if
(
list_empty
(
&
s
->
dlcs
))
{
if
(
list_empty
(
&
s
->
dlcs
))
{
s
->
state
=
BT_DISCONN
;
s
->
state
=
BT_DISCONN
;
rfcomm_send_disc
(
s
,
0
);
rfcomm_send_disc
(
s
,
0
);
rfcomm_session_clear_timer
(
s
);
}
}
break
;
break
;
...
...
net/bluetooth/sco.c
View file @
9662cbc7
...
@@ -189,7 +189,7 @@ static int sco_connect(struct sock *sk)
...
@@ -189,7 +189,7 @@ static int sco_connect(struct sock *sk)
if
(
!
hdev
)
if
(
!
hdev
)
return
-
EHOSTUNREACH
;
return
-
EHOSTUNREACH
;
hci_dev_lock
_bh
(
hdev
);
hci_dev_lock
(
hdev
);
if
(
lmp_esco_capable
(
hdev
)
&&
!
disable_esco
)
if
(
lmp_esco_capable
(
hdev
)
&&
!
disable_esco
)
type
=
ESCO_LINK
;
type
=
ESCO_LINK
;
...
@@ -225,7 +225,7 @@ static int sco_connect(struct sock *sk)
...
@@ -225,7 +225,7 @@ static int sco_connect(struct sock *sk)
}
}
done:
done:
hci_dev_unlock
_bh
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_put
(
hdev
);
hci_dev_put
(
hdev
);
return
err
;
return
err
;
}
}
...
...
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