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
dc0d633e
Commit
dc0d633e
authored
Jan 02, 2012
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
aef6c928
4ae1652e
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
496 additions
and
459 deletions
+496
-459
drivers/bluetooth/btusb.c
drivers/bluetooth/btusb.c
+3
-7
include/net/bluetooth/bluetooth.h
include/net/bluetooth/bluetooth.h
+0
-22
include/net/bluetooth/hci.h
include/net/bluetooth/hci.h
+13
-1
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_core.h
+68
-94
include/net/bluetooth/l2cap.h
include/net/bluetooth/l2cap.h
+34
-6
include/net/bluetooth/smp.h
include/net/bluetooth/smp.h
+6
-0
net/bluetooth/Kconfig
net/bluetooth/Kconfig
+9
-28
net/bluetooth/Makefile
net/bluetooth/Makefile
+2
-3
net/bluetooth/af_bluetooth.c
net/bluetooth/af_bluetooth.c
+4
-7
net/bluetooth/bnep/Kconfig
net/bluetooth/bnep/Kconfig
+1
-1
net/bluetooth/cmtp/Kconfig
net/bluetooth/cmtp/Kconfig
+1
-1
net/bluetooth/hci_conn.c
net/bluetooth/hci_conn.c
+2
-2
net/bluetooth/hci_core.c
net/bluetooth/hci_core.c
+67
-105
net/bluetooth/hci_event.c
net/bluetooth/hci_event.c
+22
-6
net/bluetooth/hidp/Kconfig
net/bluetooth/hidp/Kconfig
+1
-1
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_core.c
+26
-86
net/bluetooth/mgmt.c
net/bluetooth/mgmt.c
+9
-1
net/bluetooth/rfcomm/Kconfig
net/bluetooth/rfcomm/Kconfig
+1
-1
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/core.c
+14
-27
net/bluetooth/sco.c
net/bluetooth/sco.c
+4
-34
net/bluetooth/smp.c
net/bluetooth/smp.c
+209
-26
No files found.
drivers/bluetooth/btusb.c
View file @
dc0d633e
...
@@ -101,6 +101,7 @@ static struct usb_device_id btusb_table[] = {
...
@@ -101,6 +101,7 @@ static struct usb_device_id btusb_table[] = {
{
USB_DEVICE
(
0x0c10
,
0x0000
)
},
{
USB_DEVICE
(
0x0c10
,
0x0000
)
},
/* Broadcom BCM20702A0 */
/* Broadcom BCM20702A0 */
{
USB_DEVICE
(
0x0a5c
,
0x21e3
)
},
{
USB_DEVICE
(
0x413c
,
0x8197
)
},
{
USB_DEVICE
(
0x413c
,
0x8197
)
},
{
}
/* Terminating entry */
{
}
/* Terminating entry */
...
@@ -508,15 +509,10 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
...
@@ -508,15 +509,10 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
pipe
=
usb_rcvisocpipe
(
data
->
udev
,
data
->
isoc_rx_ep
->
bEndpointAddress
);
pipe
=
usb_rcvisocpipe
(
data
->
udev
,
data
->
isoc_rx_ep
->
bEndpointAddress
);
urb
->
dev
=
data
->
udev
;
usb_fill_int_urb
(
urb
,
data
->
udev
,
pipe
,
buf
,
size
,
btusb_isoc_complete
,
urb
->
pipe
=
pipe
;
hdev
,
data
->
isoc_rx_ep
->
bInterval
);
urb
->
context
=
hdev
;
urb
->
complete
=
btusb_isoc_complete
;
urb
->
interval
=
data
->
isoc_rx_ep
->
bInterval
;
urb
->
transfer_flags
=
URB_FREE_BUFFER
|
URB_ISO_ASAP
;
urb
->
transfer_flags
=
URB_FREE_BUFFER
|
URB_ISO_ASAP
;
urb
->
transfer_buffer
=
buf
;
urb
->
transfer_buffer_length
=
size
;
__fill_isoc_descriptor
(
urb
,
size
,
__fill_isoc_descriptor
(
urb
,
size
,
le16_to_cpu
(
data
->
isoc_rx_ep
->
wMaxPacketSize
));
le16_to_cpu
(
data
->
isoc_rx_ep
->
wMaxPacketSize
));
...
...
include/net/bluetooth/bluetooth.h
View file @
dc0d633e
...
@@ -250,32 +250,10 @@ extern void bt_sysfs_cleanup(void);
...
@@ -250,32 +250,10 @@ extern void bt_sysfs_cleanup(void);
extern
struct
dentry
*
bt_debugfs
;
extern
struct
dentry
*
bt_debugfs
;
#ifdef CONFIG_BT_L2CAP
int
l2cap_init
(
void
);
int
l2cap_init
(
void
);
void
l2cap_exit
(
void
);
void
l2cap_exit
(
void
);
#else
static
inline
int
l2cap_init
(
void
)
{
return
0
;
}
static
inline
void
l2cap_exit
(
void
)
{
}
#endif
#ifdef CONFIG_BT_SCO
int
sco_init
(
void
);
int
sco_init
(
void
);
void
sco_exit
(
void
);
void
sco_exit
(
void
);
#else
static
inline
int
sco_init
(
void
)
{
return
0
;
}
static
inline
void
sco_exit
(
void
)
{
}
#endif
#endif
/* __BLUETOOTH_H */
#endif
/* __BLUETOOTH_H */
include/net/bluetooth/hci.h
View file @
dc0d633e
...
@@ -280,6 +280,10 @@ enum {
...
@@ -280,6 +280,10 @@ enum {
#define HCI_ERROR_LOCAL_HOST_TERM 0x16
#define HCI_ERROR_LOCAL_HOST_TERM 0x16
#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18
#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18
/* Flow control modes */
#define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00
#define HCI_FLOW_CTL_MODE_BLOCK_BASED 0x01
/* ----- HCI Commands ---- */
/* ----- HCI Commands ---- */
#define HCI_OP_NOP 0x0000
#define HCI_OP_NOP 0x0000
...
@@ -800,6 +804,9 @@ struct hci_cp_le_set_scan_param {
...
@@ -800,6 +804,9 @@ struct hci_cp_le_set_scan_param {
__u8
filter_policy
;
__u8
filter_policy
;
}
__packed
;
}
__packed
;
#define LE_SCANNING_DISABLED 0x00
#define LE_SCANNING_ENABLED 0x01
#define HCI_OP_LE_SET_SCAN_ENABLE 0x200c
#define HCI_OP_LE_SET_SCAN_ENABLE 0x200c
struct
hci_cp_le_set_scan_enable
{
struct
hci_cp_le_set_scan_enable
{
__u8
enable
;
__u8
enable
;
...
@@ -975,9 +982,14 @@ struct hci_ev_role_change {
...
@@ -975,9 +982,14 @@ struct hci_ev_role_change {
}
__packed
;
}
__packed
;
#define HCI_EV_NUM_COMP_PKTS 0x13
#define HCI_EV_NUM_COMP_PKTS 0x13
struct
hci_comp_pkts_info
{
__le16
handle
;
__le16
count
;
}
__packed
;
struct
hci_ev_num_comp_pkts
{
struct
hci_ev_num_comp_pkts
{
__u8
num_hndl
;
__u8
num_hndl
;
/* variable length part */
struct
hci_comp_pkts_info
handles
[
0
];
}
__packed
;
}
__packed
;
#define HCI_EV_MODE_CHANGE 0x14
#define HCI_EV_MODE_CHANGE 0x14
...
...
include/net/bluetooth/hci_core.h
View file @
dc0d633e
...
@@ -28,10 +28,6 @@
...
@@ -28,10 +28,6 @@
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <net/bluetooth/hci.h>
#include <net/bluetooth/hci.h>
/* HCI upper protocols */
#define HCI_PROTO_L2CAP 0
#define HCI_PROTO_SCO 1
/* HCI priority */
/* HCI priority */
#define HCI_PRIO_MAX 7
#define HCI_PRIO_MAX 7
...
@@ -54,7 +50,6 @@ struct inquiry_entry {
...
@@ -54,7 +50,6 @@ struct inquiry_entry {
};
};
struct
inquiry_cache
{
struct
inquiry_cache
{
spinlock_t
lock
;
__u32
timestamp
;
__u32
timestamp
;
struct
inquiry_entry
*
list
;
struct
inquiry_entry
*
list
;
};
};
...
@@ -314,6 +309,7 @@ struct hci_conn {
...
@@ -314,6 +309,7 @@ struct hci_conn {
struct
hci_dev
*
hdev
;
struct
hci_dev
*
hdev
;
void
*
l2cap_data
;
void
*
l2cap_data
;
void
*
sco_data
;
void
*
sco_data
;
void
*
smp_conn
;
struct
hci_conn
*
link
;
struct
hci_conn
*
link
;
...
@@ -330,25 +326,31 @@ struct hci_chan {
...
@@ -330,25 +326,31 @@ struct hci_chan {
unsigned
int
sent
;
unsigned
int
sent
;
};
};
extern
struct
hci_proto
*
hci_proto
[];
extern
struct
list_head
hci_dev_list
;
extern
struct
list_head
hci_dev_list
;
extern
struct
list_head
hci_cb_list
;
extern
struct
list_head
hci_cb_list
;
extern
rwlock_t
hci_dev_list_lock
;
extern
rwlock_t
hci_dev_list_lock
;
extern
rwlock_t
hci_cb_list_lock
;
extern
rwlock_t
hci_cb_list_lock
;
/* ----- HCI interface to upper protocols ----- */
extern
int
l2cap_connect_ind
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
);
extern
int
l2cap_connect_cfm
(
struct
hci_conn
*
hcon
,
u8
status
);
extern
int
l2cap_disconn_ind
(
struct
hci_conn
*
hcon
);
extern
int
l2cap_disconn_cfm
(
struct
hci_conn
*
hcon
,
u8
reason
);
extern
int
l2cap_security_cfm
(
struct
hci_conn
*
hcon
,
u8
status
,
u8
encrypt
);
extern
int
l2cap_recv_acldata
(
struct
hci_conn
*
hcon
,
struct
sk_buff
*
skb
,
u16
flags
);
extern
int
sco_connect_ind
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
);
extern
int
sco_connect_cfm
(
struct
hci_conn
*
hcon
,
__u8
status
);
extern
int
sco_disconn_cfm
(
struct
hci_conn
*
hcon
,
__u8
reason
);
extern
int
sco_recv_scodata
(
struct
hci_conn
*
hcon
,
struct
sk_buff
*
skb
);
/* ----- Inquiry cache ----- */
/* ----- Inquiry cache ----- */
#define INQUIRY_CACHE_AGE_MAX (HZ*30)
/* 30 seconds */
#define INQUIRY_CACHE_AGE_MAX (HZ*30)
/* 30 seconds */
#define INQUIRY_ENTRY_AGE_MAX (HZ*60)
/* 60 seconds */
#define INQUIRY_ENTRY_AGE_MAX (HZ*60)
/* 60 seconds */
#define inquiry_cache_lock(c) spin_lock(&c->lock)
#define inquiry_cache_unlock(c) spin_unlock(&c->lock)
#define inquiry_cache_lock_bh(c) spin_lock_bh(&c->lock)
#define inquiry_cache_unlock_bh(c) spin_unlock_bh(&c->lock)
static
inline
void
inquiry_cache_init
(
struct
hci_dev
*
hdev
)
static
inline
void
inquiry_cache_init
(
struct
hci_dev
*
hdev
)
{
{
struct
inquiry_cache
*
c
=
&
hdev
->
inq_cache
;
struct
inquiry_cache
*
c
=
&
hdev
->
inq_cache
;
spin_lock_init
(
&
c
->
lock
);
c
->
list
=
NULL
;
c
->
list
=
NULL
;
}
}
...
@@ -677,53 +679,40 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
...
@@ -677,53 +679,40 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_host_le_capable(dev) ((dev)->extfeatures[0] & LMP_HOST_LE)
#define lmp_host_le_capable(dev) ((dev)->extfeatures[0] & LMP_HOST_LE)
/* ----- HCI protocols ----- */
/* ----- HCI protocols ----- */
struct
hci_proto
{
char
*
name
;
unsigned
int
id
;
unsigned
long
flags
;
void
*
priv
;
int
(
*
connect_ind
)
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
__u8
type
);
int
(
*
connect_cfm
)
(
struct
hci_conn
*
conn
,
__u8
status
);
int
(
*
disconn_ind
)
(
struct
hci_conn
*
conn
);
int
(
*
disconn_cfm
)
(
struct
hci_conn
*
conn
,
__u8
reason
);
int
(
*
recv_acldata
)
(
struct
hci_conn
*
conn
,
struct
sk_buff
*
skb
,
__u16
flags
);
int
(
*
recv_scodata
)
(
struct
hci_conn
*
conn
,
struct
sk_buff
*
skb
);
int
(
*
security_cfm
)
(
struct
hci_conn
*
conn
,
__u8
status
,
__u8
encrypt
);
};
static
inline
int
hci_proto_connect_ind
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
static
inline
int
hci_proto_connect_ind
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
__u8
type
)
__u8
type
)
{
{
register
struct
hci_proto
*
hp
;
switch
(
type
)
{
int
mask
=
0
;
case
ACL_LINK
:
return
l2cap_connect_ind
(
hdev
,
bdaddr
);
hp
=
hci_proto
[
HCI_PROTO_L2CAP
];
if
(
hp
&&
hp
->
connect_ind
)
mask
|=
hp
->
connect_ind
(
hdev
,
bdaddr
,
type
);
hp
=
hci_proto
[
HCI_PROTO_SCO
];
case
SCO_LINK
:
if
(
hp
&&
hp
->
connect_ind
)
case
ESCO_LINK
:
mask
|=
hp
->
connect_ind
(
hdev
,
bdaddr
,
type
);
return
sco_connect_ind
(
hdev
,
bdaddr
);
return
mask
;
default:
BT_ERR
(
"unknown link type %d"
,
type
);
return
-
EINVAL
;
}
}
}
static
inline
void
hci_proto_connect_cfm
(
struct
hci_conn
*
conn
,
__u8
status
)
static
inline
void
hci_proto_connect_cfm
(
struct
hci_conn
*
conn
,
__u8
status
)
{
{
register
struct
hci_proto
*
hp
;
switch
(
conn
->
type
)
{
case
ACL_LINK
:
case
LE_LINK
:
l2cap_connect_cfm
(
conn
,
status
);
break
;
hp
=
hci_proto
[
HCI_PROTO_L2CAP
];
case
SCO_LINK
:
if
(
hp
&&
hp
->
connect_cfm
)
case
ESCO_LINK
:
hp
->
connect_cfm
(
conn
,
status
);
sco_connect_cfm
(
conn
,
status
);
break
;
hp
=
hci_proto
[
HCI_PROTO_SCO
];
default:
if
(
hp
&&
hp
->
connect_cfm
)
BT_ERR
(
"unknown link type %d"
,
conn
->
type
);
hp
->
connect_cfm
(
conn
,
status
);
break
;
}
if
(
conn
->
connect_cfm_cb
)
if
(
conn
->
connect_cfm_cb
)
conn
->
connect_cfm_cb
(
conn
,
status
);
conn
->
connect_cfm_cb
(
conn
,
status
);
...
@@ -731,31 +720,29 @@ static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
...
@@ -731,31 +720,29 @@ static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
static
inline
int
hci_proto_disconn_ind
(
struct
hci_conn
*
conn
)
static
inline
int
hci_proto_disconn_ind
(
struct
hci_conn
*
conn
)
{
{
register
struct
hci_proto
*
hp
;
if
(
conn
->
type
!=
ACL_LINK
&&
conn
->
type
!=
LE_LINK
)
int
reason
=
HCI_ERROR_REMOTE_USER_TERM
;
return
HCI_ERROR_REMOTE_USER_TERM
;
hp
=
hci_proto
[
HCI_PROTO_L2CAP
];
return
l2cap_disconn_ind
(
conn
);
if
(
hp
&&
hp
->
disconn_ind
)
reason
=
hp
->
disconn_ind
(
conn
);
hp
=
hci_proto
[
HCI_PROTO_SCO
];
if
(
hp
&&
hp
->
disconn_ind
)
reason
=
hp
->
disconn_ind
(
conn
);
return
reason
;
}
}
static
inline
void
hci_proto_disconn_cfm
(
struct
hci_conn
*
conn
,
__u8
reason
)
static
inline
void
hci_proto_disconn_cfm
(
struct
hci_conn
*
conn
,
__u8
reason
)
{
{
register
struct
hci_proto
*
hp
;
switch
(
conn
->
type
)
{
case
ACL_LINK
:
case
LE_LINK
:
l2cap_disconn_cfm
(
conn
,
reason
);
break
;
hp
=
hci_proto
[
HCI_PROTO_L2CAP
];
case
SCO_LINK
:
if
(
hp
&&
hp
->
disconn_cfm
)
case
ESCO_LINK
:
hp
->
disconn_cfm
(
conn
,
reason
);
sco_disconn_cfm
(
conn
,
reason
);
break
;
hp
=
hci_proto
[
HCI_PROTO_SCO
];
default:
if
(
hp
&&
hp
->
disconn_cfm
)
BT_ERR
(
"unknown link type %d"
,
conn
->
type
);
hp
->
disconn_cfm
(
conn
,
reason
);
break
;
}
if
(
conn
->
disconn_cfm_cb
)
if
(
conn
->
disconn_cfm_cb
)
conn
->
disconn_cfm_cb
(
conn
,
reason
);
conn
->
disconn_cfm_cb
(
conn
,
reason
);
...
@@ -763,21 +750,16 @@ static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
...
@@ -763,21 +750,16 @@ static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
static
inline
void
hci_proto_auth_cfm
(
struct
hci_conn
*
conn
,
__u8
status
)
static
inline
void
hci_proto_auth_cfm
(
struct
hci_conn
*
conn
,
__u8
status
)
{
{
register
struct
hci_proto
*
hp
;
__u8
encrypt
;
__u8
encrypt
;
if
(
conn
->
type
!=
ACL_LINK
&&
conn
->
type
!=
LE_LINK
)
return
;
if
(
test_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
pend
))
if
(
test_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
pend
))
return
;
return
;
encrypt
=
(
conn
->
link_mode
&
HCI_LM_ENCRYPT
)
?
0x01
:
0x00
;
encrypt
=
(
conn
->
link_mode
&
HCI_LM_ENCRYPT
)
?
0x01
:
0x00
;
l2cap_security_cfm
(
conn
,
status
,
encrypt
);
hp
=
hci_proto
[
HCI_PROTO_L2CAP
];
if
(
hp
&&
hp
->
security_cfm
)
hp
->
security_cfm
(
conn
,
status
,
encrypt
);
hp
=
hci_proto
[
HCI_PROTO_SCO
];
if
(
hp
&&
hp
->
security_cfm
)
hp
->
security_cfm
(
conn
,
status
,
encrypt
);
if
(
conn
->
security_cfm_cb
)
if
(
conn
->
security_cfm_cb
)
conn
->
security_cfm_cb
(
conn
,
status
);
conn
->
security_cfm_cb
(
conn
,
status
);
...
@@ -786,23 +768,15 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
...
@@ -786,23 +768,15 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
static
inline
void
hci_proto_encrypt_cfm
(
struct
hci_conn
*
conn
,
__u8
status
,
static
inline
void
hci_proto_encrypt_cfm
(
struct
hci_conn
*
conn
,
__u8
status
,
__u8
encrypt
)
__u8
encrypt
)
{
{
register
struct
hci_proto
*
hp
;
if
(
conn
->
type
!=
ACL_LINK
&&
conn
->
type
!=
LE_LINK
)
return
;
hp
=
hci_proto
[
HCI_PROTO_L2CAP
];
if
(
hp
&&
hp
->
security_cfm
)
hp
->
security_cfm
(
conn
,
status
,
encrypt
);
hp
=
hci_proto
[
HCI_PROTO_SCO
];
l2cap_security_cfm
(
conn
,
status
,
encrypt
);
if
(
hp
&&
hp
->
security_cfm
)
hp
->
security_cfm
(
conn
,
status
,
encrypt
);
if
(
conn
->
security_cfm_cb
)
if
(
conn
->
security_cfm_cb
)
conn
->
security_cfm_cb
(
conn
,
status
);
conn
->
security_cfm_cb
(
conn
,
status
);
}
}
int
hci_register_proto
(
struct
hci_proto
*
hproto
);
int
hci_unregister_proto
(
struct
hci_proto
*
hproto
);
/* ----- HCI callbacks ----- */
/* ----- HCI callbacks ----- */
struct
hci_cb
{
struct
hci_cb
{
struct
list_head
list
;
struct
list_head
list
;
...
@@ -827,13 +801,13 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
...
@@ -827,13 +801,13 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
encrypt
=
(
conn
->
link_mode
&
HCI_LM_ENCRYPT
)
?
0x01
:
0x00
;
encrypt
=
(
conn
->
link_mode
&
HCI_LM_ENCRYPT
)
?
0x01
:
0x00
;
read_lock
_bh
(
&
hci_cb_list_lock
);
read_lock
(
&
hci_cb_list_lock
);
list_for_each
(
p
,
&
hci_cb_list
)
{
list_for_each
(
p
,
&
hci_cb_list
)
{
struct
hci_cb
*
cb
=
list_entry
(
p
,
struct
hci_cb
,
list
);
struct
hci_cb
*
cb
=
list_entry
(
p
,
struct
hci_cb
,
list
);
if
(
cb
->
security_cfm
)
if
(
cb
->
security_cfm
)
cb
->
security_cfm
(
conn
,
status
,
encrypt
);
cb
->
security_cfm
(
conn
,
status
,
encrypt
);
}
}
read_unlock
_bh
(
&
hci_cb_list_lock
);
read_unlock
(
&
hci_cb_list_lock
);
}
}
static
inline
void
hci_encrypt_cfm
(
struct
hci_conn
*
conn
,
__u8
status
,
static
inline
void
hci_encrypt_cfm
(
struct
hci_conn
*
conn
,
__u8
status
,
...
@@ -849,26 +823,26 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
...
@@ -849,26 +823,26 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
hci_proto_encrypt_cfm
(
conn
,
status
,
encrypt
);
hci_proto_encrypt_cfm
(
conn
,
status
,
encrypt
);
read_lock
_bh
(
&
hci_cb_list_lock
);
read_lock
(
&
hci_cb_list_lock
);
list_for_each
(
p
,
&
hci_cb_list
)
{
list_for_each
(
p
,
&
hci_cb_list
)
{
struct
hci_cb
*
cb
=
list_entry
(
p
,
struct
hci_cb
,
list
);
struct
hci_cb
*
cb
=
list_entry
(
p
,
struct
hci_cb
,
list
);
if
(
cb
->
security_cfm
)
if
(
cb
->
security_cfm
)
cb
->
security_cfm
(
conn
,
status
,
encrypt
);
cb
->
security_cfm
(
conn
,
status
,
encrypt
);
}
}
read_unlock
_bh
(
&
hci_cb_list_lock
);
read_unlock
(
&
hci_cb_list_lock
);
}
}
static
inline
void
hci_key_change_cfm
(
struct
hci_conn
*
conn
,
__u8
status
)
static
inline
void
hci_key_change_cfm
(
struct
hci_conn
*
conn
,
__u8
status
)
{
{
struct
list_head
*
p
;
struct
list_head
*
p
;
read_lock
_bh
(
&
hci_cb_list_lock
);
read_lock
(
&
hci_cb_list_lock
);
list_for_each
(
p
,
&
hci_cb_list
)
{
list_for_each
(
p
,
&
hci_cb_list
)
{
struct
hci_cb
*
cb
=
list_entry
(
p
,
struct
hci_cb
,
list
);
struct
hci_cb
*
cb
=
list_entry
(
p
,
struct
hci_cb
,
list
);
if
(
cb
->
key_change_cfm
)
if
(
cb
->
key_change_cfm
)
cb
->
key_change_cfm
(
conn
,
status
);
cb
->
key_change_cfm
(
conn
,
status
);
}
}
read_unlock
_bh
(
&
hci_cb_list_lock
);
read_unlock
(
&
hci_cb_list_lock
);
}
}
static
inline
void
hci_role_switch_cfm
(
struct
hci_conn
*
conn
,
__u8
status
,
static
inline
void
hci_role_switch_cfm
(
struct
hci_conn
*
conn
,
__u8
status
,
...
@@ -876,13 +850,13 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
...
@@ -876,13 +850,13 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
{
{
struct
list_head
*
p
;
struct
list_head
*
p
;
read_lock
_bh
(
&
hci_cb_list_lock
);
read_lock
(
&
hci_cb_list_lock
);
list_for_each
(
p
,
&
hci_cb_list
)
{
list_for_each
(
p
,
&
hci_cb_list
)
{
struct
hci_cb
*
cb
=
list_entry
(
p
,
struct
hci_cb
,
list
);
struct
hci_cb
*
cb
=
list_entry
(
p
,
struct
hci_cb
,
list
);
if
(
cb
->
role_switch_cfm
)
if
(
cb
->
role_switch_cfm
)
cb
->
role_switch_cfm
(
conn
,
status
,
role
);
cb
->
role_switch_cfm
(
conn
,
status
,
role
);
}
}
read_unlock
_bh
(
&
hci_cb_list_lock
);
read_unlock
(
&
hci_cb_list_lock
);
}
}
int
hci_register_cb
(
struct
hci_cb
*
hcb
);
int
hci_register_cb
(
struct
hci_cb
*
hcb
);
...
...
include/net/bluetooth/l2cap.h
View file @
dc0d633e
...
@@ -522,7 +522,7 @@ struct l2cap_conn {
...
@@ -522,7 +522,7 @@ struct l2cap_conn {
__u8
info_state
;
__u8
info_state
;
__u8
info_ident
;
__u8
info_ident
;
struct
delayed_work
info_
work
;
struct
delayed_work
info_
timer
;
spinlock_t
lock
;
spinlock_t
lock
;
...
@@ -532,7 +532,7 @@ struct l2cap_conn {
...
@@ -532,7 +532,7 @@ struct l2cap_conn {
__u8
disc_reason
;
__u8
disc_reason
;
struct
timer_list
security_timer
;
struct
delayed_work
security_timer
;
struct
smp_chan
*
smp_chan
;
struct
smp_chan
*
smp_chan
;
struct
list_head
chan_l
;
struct
list_head
chan_l
;
...
@@ -595,17 +595,45 @@ enum {
...
@@ -595,17 +595,45 @@ enum {
FLAG_EFS_ENABLE
,
FLAG_EFS_ENABLE
,
};
};
static
inline
void
l2cap_chan_hold
(
struct
l2cap_chan
*
c
)
{
atomic_inc
(
&
c
->
refcnt
);
}
static
inline
void
l2cap_chan_put
(
struct
l2cap_chan
*
c
)
{
if
(
atomic_dec_and_test
(
&
c
->
refcnt
))
kfree
(
c
);
}
static
inline
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
);
if
(
!
__cancel_delayed_work
(
work
))
l2cap_chan_hold
(
chan
);
schedule_delayed_work
(
work
,
timeout
);
}
static
inline
void
l2cap_clear_timer
(
struct
l2cap_chan
*
chan
,
struct
delayed_work
*
work
)
{
if
(
__cancel_delayed_work
(
work
))
l2cap_chan_put
(
chan
);
}
#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->chan_timer)
#define __clear_chan_timer(c) l2cap_clear_timer(
c,
&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->retrans_timer)
#define __clear_retrans_timer(c) l2cap_clear_timer(
c,
&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->monitor_timer)
#define __clear_monitor_timer(c) l2cap_clear_timer(
c,
&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->ack_timer)
#define __clear_ack_timer(c) l2cap_clear_timer(
c,
&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
)
{
{
...
...
include/net/bluetooth/smp.h
View file @
dc0d633e
...
@@ -115,6 +115,10 @@ struct smp_cmd_security_req {
...
@@ -115,6 +115,10 @@ struct smp_cmd_security_req {
#define SMP_MIN_ENC_KEY_SIZE 7
#define SMP_MIN_ENC_KEY_SIZE 7
#define SMP_MAX_ENC_KEY_SIZE 16
#define SMP_MAX_ENC_KEY_SIZE 16
#define SMP_FLAG_TK_VALID 1
#define SMP_FLAG_CFM_PENDING 2
#define SMP_FLAG_MITM_AUTH 3
struct
smp_chan
{
struct
smp_chan
{
struct
l2cap_conn
*
conn
;
struct
l2cap_conn
*
conn
;
u8
preq
[
7
];
/* SMP Pairing Request */
u8
preq
[
7
];
/* SMP Pairing Request */
...
@@ -124,6 +128,7 @@ struct smp_chan {
...
@@ -124,6 +128,7 @@ struct smp_chan {
u8
pcnf
[
16
];
/* SMP Pairing Confirm */
u8
pcnf
[
16
];
/* SMP Pairing Confirm */
u8
tk
[
16
];
/* SMP Temporary Key */
u8
tk
[
16
];
/* SMP Temporary Key */
u8
smp_key_size
;
u8
smp_key_size
;
unsigned
long
smp_flags
;
struct
crypto_blkcipher
*
tfm
;
struct
crypto_blkcipher
*
tfm
;
struct
work_struct
confirm
;
struct
work_struct
confirm
;
struct
work_struct
random
;
struct
work_struct
random
;
...
@@ -134,6 +139,7 @@ struct smp_chan {
...
@@ -134,6 +139,7 @@ struct smp_chan {
int
smp_conn_security
(
struct
l2cap_conn
*
conn
,
__u8
sec_level
);
int
smp_conn_security
(
struct
l2cap_conn
*
conn
,
__u8
sec_level
);
int
smp_sig_channel
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
);
int
smp_sig_channel
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
);
int
smp_distribute_keys
(
struct
l2cap_conn
*
conn
,
__u8
force
);
int
smp_distribute_keys
(
struct
l2cap_conn
*
conn
,
__u8
force
);
int
smp_user_confirm_reply
(
struct
hci_conn
*
conn
,
u16
mgmt_op
,
__le32
passkey
);
void
smp_chan_destroy
(
struct
l2cap_conn
*
conn
);
void
smp_chan_destroy
(
struct
l2cap_conn
*
conn
);
...
...
net/bluetooth/Kconfig
View file @
dc0d633e
...
@@ -6,7 +6,11 @@ menuconfig BT
...
@@ -6,7 +6,11 @@ menuconfig BT
tristate "Bluetooth subsystem support"
tristate "Bluetooth subsystem support"
depends on NET && !S390
depends on NET && !S390
depends on RFKILL || !RFKILL
depends on RFKILL || !RFKILL
select CRC16
select CRYPTO
select CRYPTO
select CRYPTO_BLKCIPHER
select CRYPTO_AES
select CRYPTO_ECB
help
help
Bluetooth is low-cost, low-power, short-range wireless technology.
Bluetooth is low-cost, low-power, short-range wireless technology.
It was designed as a replacement for cables and other short-range
It was designed as a replacement for cables and other short-range
...
@@ -15,10 +19,12 @@ menuconfig BT
...
@@ -15,10 +19,12 @@ menuconfig BT
Bluetooth can be found at <http://www.bluetooth.com/>.
Bluetooth can be found at <http://www.bluetooth.com/>.
Linux Bluetooth subsystem consist of several layers:
Linux Bluetooth subsystem consist of several layers:
Bluetooth Core (HCI device and connection manager, scheduler)
Bluetooth Core
HCI device and connection manager, scheduler
SCO audio links
L2CAP (Logical Link Control and Adaptation Protocol)
SMP (Security Manager Protocol) on LE (Low Energy) links
HCI Device drivers (Interface to the hardware)
HCI Device drivers (Interface to the hardware)
SCO Module (SCO audio links)
L2CAP Module (Logical Link Control and Adaptation Protocol)
RFCOMM Module (RFCOMM Protocol)
RFCOMM Module (RFCOMM Protocol)
BNEP Module (Bluetooth Network Encapsulation Protocol)
BNEP Module (Bluetooth Network Encapsulation Protocol)
CMTP Module (CAPI Message Transport Protocol)
CMTP Module (CAPI Message Transport Protocol)
...
@@ -33,31 +39,6 @@ menuconfig BT
...
@@ -33,31 +39,6 @@ menuconfig BT
to Bluetooth kernel modules are provided in the BlueZ packages. For
to Bluetooth kernel modules are provided in the BlueZ packages. For
more information, see <http://www.bluez.org/>.
more information, see <http://www.bluez.org/>.
if BT != n
config BT_L2CAP
bool "L2CAP protocol support"
select CRC16
select CRYPTO
select CRYPTO_BLKCIPHER
select CRYPTO_AES
select CRYPTO_ECB
help
L2CAP (Logical Link Control and Adaptation Protocol) provides
connection oriented and connection-less data transport. L2CAP
support is required for most Bluetooth applications.
Also included is support for SMP (Security Manager Protocol) which
is the security layer on top of LE (Low Energy) links.
config BT_SCO
bool "SCO links support"
help
SCO link provides voice transport over Bluetooth. SCO support is
required for voice applications like Headset and Audio.
endif
source "net/bluetooth/rfcomm/Kconfig"
source "net/bluetooth/rfcomm/Kconfig"
source "net/bluetooth/bnep/Kconfig"
source "net/bluetooth/bnep/Kconfig"
...
...
net/bluetooth/Makefile
View file @
dc0d633e
...
@@ -8,6 +8,5 @@ obj-$(CONFIG_BT_BNEP) += bnep/
...
@@ -8,6 +8,5 @@ obj-$(CONFIG_BT_BNEP) += bnep/
obj-$(CONFIG_BT_CMTP)
+=
cmtp/
obj-$(CONFIG_BT_CMTP)
+=
cmtp/
obj-$(CONFIG_BT_HIDP)
+=
hidp/
obj-$(CONFIG_BT_HIDP)
+=
hidp/
bluetooth-y
:=
af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o hci_sock.o hci_sysfs.o lib.o
bluetooth-y
:=
af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o
\
bluetooth-$(CONFIG_BT_L2CAP)
+=
l2cap_core.o l2cap_sock.o smp.o
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o
bluetooth-$(CONFIG_BT_SCO)
+=
sco.o
net/bluetooth/af_bluetooth.c
View file @
dc0d633e
...
@@ -199,15 +199,14 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
...
@@ -199,15 +199,14 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
BT_DBG
(
"parent %p"
,
parent
);
BT_DBG
(
"parent %p"
,
parent
);
local_bh_disable
();
list_for_each_safe
(
p
,
n
,
&
bt_sk
(
parent
)
->
accept_q
)
{
list_for_each_safe
(
p
,
n
,
&
bt_sk
(
parent
)
->
accept_q
)
{
sk
=
(
struct
sock
*
)
list_entry
(
p
,
struct
bt_sock
,
accept_q
);
sk
=
(
struct
sock
*
)
list_entry
(
p
,
struct
bt_sock
,
accept_q
);
bh_
lock_sock
(
sk
);
lock_sock
(
sk
);
/* FIXME: Is this check still needed */
/* FIXME: Is this check still needed */
if
(
sk
->
sk_state
==
BT_CLOSED
)
{
if
(
sk
->
sk_state
==
BT_CLOSED
)
{
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
bt_accept_unlink
(
sk
);
bt_accept_unlink
(
sk
);
continue
;
continue
;
}
}
...
@@ -218,14 +217,12 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
...
@@ -218,14 +217,12 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
if
(
newsock
)
if
(
newsock
)
sock_graft
(
sk
,
newsock
);
sock_graft
(
sk
,
newsock
);
bh_unlock_sock
(
sk
);
release_sock
(
sk
);
local_bh_enable
();
return
sk
;
return
sk
;
}
}
bh_unlock
_sock
(
sk
);
release
_sock
(
sk
);
}
}
local_bh_enable
();
return
NULL
;
return
NULL
;
}
}
...
...
net/bluetooth/bnep/Kconfig
View file @
dc0d633e
config BT_BNEP
config BT_BNEP
tristate "BNEP protocol support"
tristate "BNEP protocol support"
depends on BT
&& BT_L2CAP
depends on BT
select CRC32
select CRC32
help
help
BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
...
...
net/bluetooth/cmtp/Kconfig
View file @
dc0d633e
config BT_CMTP
config BT_CMTP
tristate "CMTP protocol support"
tristate "CMTP protocol support"
depends on BT &&
BT_L2CAP &&
ISDN_CAPI
depends on BT && ISDN_CAPI
help
help
CMTP (CAPI Message Transport Protocol) is a transport layer
CMTP (CAPI Message Transport Protocol) is a transport layer
for CAPI messages. CMTP is required for the Bluetooth Common
for CAPI messages. CMTP is required for the Bluetooth Common
...
...
net/bluetooth/hci_conn.c
View file @
dc0d633e
...
@@ -487,7 +487,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
...
@@ -487,7 +487,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
BT_DBG
(
"%s -> %s"
,
batostr
(
src
),
batostr
(
dst
));
BT_DBG
(
"%s -> %s"
,
batostr
(
src
),
batostr
(
dst
));
read_lock
_bh
(
&
hci_dev_list_lock
);
read_lock
(
&
hci_dev_list_lock
);
list_for_each_entry
(
d
,
&
hci_dev_list
,
list
)
{
list_for_each_entry
(
d
,
&
hci_dev_list
,
list
)
{
if
(
!
test_bit
(
HCI_UP
,
&
d
->
flags
)
||
test_bit
(
HCI_RAW
,
&
d
->
flags
))
if
(
!
test_bit
(
HCI_UP
,
&
d
->
flags
)
||
test_bit
(
HCI_RAW
,
&
d
->
flags
))
...
@@ -512,7 +512,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
...
@@ -512,7 +512,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
if
(
hdev
)
if
(
hdev
)
hdev
=
hci_dev_hold
(
hdev
);
hdev
=
hci_dev_hold
(
hdev
);
read_unlock
_bh
(
&
hci_dev_list_lock
);
read_unlock
(
&
hci_dev_list_lock
);
return
hdev
;
return
hdev
;
}
}
EXPORT_SYMBOL
(
hci_get_route
);
EXPORT_SYMBOL
(
hci_get_route
);
...
...
net/bluetooth/hci_core.c
View file @
dc0d633e
...
@@ -61,8 +61,6 @@ static void hci_rx_work(struct work_struct *work);
...
@@ -61,8 +61,6 @@ static void hci_rx_work(struct work_struct *work);
static
void
hci_cmd_work
(
struct
work_struct
*
work
);
static
void
hci_cmd_work
(
struct
work_struct
*
work
);
static
void
hci_tx_work
(
struct
work_struct
*
work
);
static
void
hci_tx_work
(
struct
work_struct
*
work
);
static
DEFINE_MUTEX
(
hci_task_lock
);
/* HCI device list */
/* HCI device list */
LIST_HEAD
(
hci_dev_list
);
LIST_HEAD
(
hci_dev_list
);
DEFINE_RWLOCK
(
hci_dev_list_lock
);
DEFINE_RWLOCK
(
hci_dev_list_lock
);
...
@@ -71,10 +69,6 @@ DEFINE_RWLOCK(hci_dev_list_lock);
...
@@ -71,10 +69,6 @@ DEFINE_RWLOCK(hci_dev_list_lock);
LIST_HEAD
(
hci_cb_list
);
LIST_HEAD
(
hci_cb_list
);
DEFINE_RWLOCK
(
hci_cb_list_lock
);
DEFINE_RWLOCK
(
hci_cb_list_lock
);
/* HCI protocols */
#define HCI_MAX_PROTO 2
struct
hci_proto
*
hci_proto
[
HCI_MAX_PROTO
];
/* HCI notifiers list */
/* HCI notifiers list */
static
ATOMIC_NOTIFIER_HEAD
(
hci_notifier
);
static
ATOMIC_NOTIFIER_HEAD
(
hci_notifier
);
...
@@ -193,33 +187,20 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
...
@@ -193,33 +187,20 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
hci_send_cmd
(
hdev
,
HCI_OP_RESET
,
0
,
NULL
);
hci_send_cmd
(
hdev
,
HCI_OP_RESET
,
0
,
NULL
);
}
}
static
void
hci_init_req
(
struct
hci_dev
*
hdev
,
unsigned
long
opt
)
static
void
bredr_init
(
struct
hci_dev
*
hdev
)
{
{
struct
hci_cp_delete_stored_link_key
cp
;
struct
hci_cp_delete_stored_link_key
cp
;
struct
sk_buff
*
skb
;
__le16
param
;
__le16
param
;
__u8
flt_type
;
__u8
flt_type
;
BT_DBG
(
"%s %ld"
,
hdev
->
name
,
opt
);
hdev
->
flow_ctl_mode
=
HCI_FLOW_CTL_MODE_PACKET_BASED
;
/* Driver initialization */
/* Special commands */
while
((
skb
=
skb_dequeue
(
&
hdev
->
driver_init
)))
{
bt_cb
(
skb
)
->
pkt_type
=
HCI_COMMAND_PKT
;
skb
->
dev
=
(
void
*
)
hdev
;
skb_queue_tail
(
&
hdev
->
cmd_q
,
skb
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
cmd_work
);
}
skb_queue_purge
(
&
hdev
->
driver_init
);
/* Mandatory initialization */
/* Mandatory initialization */
/* Reset */
/* Reset */
if
(
!
test_bit
(
HCI_QUIRK_NO_RESET
,
&
hdev
->
quirks
))
{
if
(
!
test_bit
(
HCI_QUIRK_NO_RESET
,
&
hdev
->
quirks
))
{
set_bit
(
HCI_RESET
,
&
hdev
->
flags
);
set_bit
(
HCI_RESET
,
&
hdev
->
flags
);
hci_send_cmd
(
hdev
,
HCI_OP_RESET
,
0
,
NULL
);
hci_send_cmd
(
hdev
,
HCI_OP_RESET
,
0
,
NULL
);
}
}
/* Read Local Supported Features */
/* Read Local Supported Features */
...
@@ -258,6 +239,51 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
...
@@ -258,6 +239,51 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
hci_send_cmd
(
hdev
,
HCI_OP_DELETE_STORED_LINK_KEY
,
sizeof
(
cp
),
&
cp
);
hci_send_cmd
(
hdev
,
HCI_OP_DELETE_STORED_LINK_KEY
,
sizeof
(
cp
),
&
cp
);
}
}
static
void
amp_init
(
struct
hci_dev
*
hdev
)
{
hdev
->
flow_ctl_mode
=
HCI_FLOW_CTL_MODE_BLOCK_BASED
;
/* Reset */
hci_send_cmd
(
hdev
,
HCI_OP_RESET
,
0
,
NULL
);
/* Read Local Version */
hci_send_cmd
(
hdev
,
HCI_OP_READ_LOCAL_VERSION
,
0
,
NULL
);
}
static
void
hci_init_req
(
struct
hci_dev
*
hdev
,
unsigned
long
opt
)
{
struct
sk_buff
*
skb
;
BT_DBG
(
"%s %ld"
,
hdev
->
name
,
opt
);
/* Driver initialization */
/* Special commands */
while
((
skb
=
skb_dequeue
(
&
hdev
->
driver_init
)))
{
bt_cb
(
skb
)
->
pkt_type
=
HCI_COMMAND_PKT
;
skb
->
dev
=
(
void
*
)
hdev
;
skb_queue_tail
(
&
hdev
->
cmd_q
,
skb
);
queue_work
(
hdev
->
workqueue
,
&
hdev
->
cmd_work
);
}
skb_queue_purge
(
&
hdev
->
driver_init
);
switch
(
hdev
->
dev_type
)
{
case
HCI_BREDR
:
bredr_init
(
hdev
);
break
;
case
HCI_AMP
:
amp_init
(
hdev
);
break
;
default:
BT_ERR
(
"Unknown device type %d"
,
hdev
->
dev_type
);
break
;
}
}
static
void
hci_le_init_req
(
struct
hci_dev
*
hdev
,
unsigned
long
opt
)
static
void
hci_le_init_req
(
struct
hci_dev
*
hdev
,
unsigned
long
opt
)
{
{
BT_DBG
(
"%s"
,
hdev
->
name
);
BT_DBG
(
"%s"
,
hdev
->
name
);
...
@@ -818,7 +844,7 @@ int hci_get_dev_list(void __user *arg)
...
@@ -818,7 +844,7 @@ int hci_get_dev_list(void __user *arg)
dr
=
dl
->
dev_req
;
dr
=
dl
->
dev_req
;
read_lock
_bh
(
&
hci_dev_list_lock
);
read_lock
(
&
hci_dev_list_lock
);
list_for_each_entry
(
hdev
,
&
hci_dev_list
,
list
)
{
list_for_each_entry
(
hdev
,
&
hci_dev_list
,
list
)
{
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
);
...
@@ -832,7 +858,7 @@ int hci_get_dev_list(void __user *arg)
...
@@ -832,7 +858,7 @@ int hci_get_dev_list(void __user *arg)
if
(
++
n
>=
dev_num
)
if
(
++
n
>=
dev_num
)
break
;
break
;
}
}
read_unlock
_bh
(
&
hci_dev_list_lock
);
read_unlock
(
&
hci_dev_list_lock
);
dl
->
dev_num
=
n
;
dl
->
dev_num
=
n
;
size
=
sizeof
(
*
dl
)
+
n
*
sizeof
(
*
dr
);
size
=
sizeof
(
*
dl
)
+
n
*
sizeof
(
*
dr
);
...
@@ -1432,7 +1458,7 @@ int hci_register_dev(struct hci_dev *hdev)
...
@@ -1432,7 +1458,7 @@ int hci_register_dev(struct hci_dev *hdev)
*/
*/
id
=
(
hdev
->
dev_type
==
HCI_BREDR
)
?
0
:
1
;
id
=
(
hdev
->
dev_type
==
HCI_BREDR
)
?
0
:
1
;
write_lock
_bh
(
&
hci_dev_list_lock
);
write_lock
(
&
hci_dev_list_lock
);
/* Find first available device id */
/* Find first available device id */
list_for_each
(
p
,
&
hci_dev_list
)
{
list_for_each
(
p
,
&
hci_dev_list
)
{
...
@@ -1502,7 +1528,7 @@ int hci_register_dev(struct hci_dev *hdev)
...
@@ -1502,7 +1528,7 @@ int hci_register_dev(struct hci_dev *hdev)
atomic_set
(
&
hdev
->
promisc
,
0
);
atomic_set
(
&
hdev
->
promisc
,
0
);
write_unlock
_bh
(
&
hci_dev_list_lock
);
write_unlock
(
&
hci_dev_list_lock
);
hdev
->
workqueue
=
alloc_workqueue
(
hdev
->
name
,
WQ_HIGHPRI
|
WQ_UNBOUND
|
hdev
->
workqueue
=
alloc_workqueue
(
hdev
->
name
,
WQ_HIGHPRI
|
WQ_UNBOUND
|
WQ_MEM_RECLAIM
,
1
);
WQ_MEM_RECLAIM
,
1
);
...
@@ -1535,9 +1561,9 @@ int hci_register_dev(struct hci_dev *hdev)
...
@@ -1535,9 +1561,9 @@ int hci_register_dev(struct hci_dev *hdev)
err_wqueue:
err_wqueue:
destroy_workqueue
(
hdev
->
workqueue
);
destroy_workqueue
(
hdev
->
workqueue
);
err:
err:
write_lock
_bh
(
&
hci_dev_list_lock
);
write_lock
(
&
hci_dev_list_lock
);
list_del
(
&
hdev
->
list
);
list_del
(
&
hdev
->
list
);
write_unlock
_bh
(
&
hci_dev_list_lock
);
write_unlock
(
&
hci_dev_list_lock
);
return
error
;
return
error
;
}
}
...
@@ -1550,9 +1576,9 @@ void hci_unregister_dev(struct hci_dev *hdev)
...
@@ -1550,9 +1576,9 @@ void hci_unregister_dev(struct hci_dev *hdev)
BT_DBG
(
"%p name %s bus %d"
,
hdev
,
hdev
->
name
,
hdev
->
bus
);
BT_DBG
(
"%p name %s bus %d"
,
hdev
,
hdev
->
name
,
hdev
->
bus
);
write_lock
_bh
(
&
hci_dev_list_lock
);
write_lock
(
&
hci_dev_list_lock
);
list_del
(
&
hdev
->
list
);
list_del
(
&
hdev
->
list
);
write_unlock
_bh
(
&
hci_dev_list_lock
);
write_unlock
(
&
hci_dev_list_lock
);
hci_dev_do_close
(
hdev
);
hci_dev_do_close
(
hdev
);
...
@@ -1800,59 +1826,13 @@ EXPORT_SYMBOL(hci_recv_stream_fragment);
...
@@ -1800,59 +1826,13 @@ EXPORT_SYMBOL(hci_recv_stream_fragment);
/* ---- Interface to upper protocols ---- */
/* ---- Interface to upper protocols ---- */
/* Register/Unregister protocols.
* hci_task_lock is used to ensure that no tasks are running. */
int
hci_register_proto
(
struct
hci_proto
*
hp
)
{
int
err
=
0
;
BT_DBG
(
"%p name %s id %d"
,
hp
,
hp
->
name
,
hp
->
id
);
if
(
hp
->
id
>=
HCI_MAX_PROTO
)
return
-
EINVAL
;
mutex_lock
(
&
hci_task_lock
);
if
(
!
hci_proto
[
hp
->
id
])
hci_proto
[
hp
->
id
]
=
hp
;
else
err
=
-
EEXIST
;
mutex_unlock
(
&
hci_task_lock
);
return
err
;
}
EXPORT_SYMBOL
(
hci_register_proto
);
int
hci_unregister_proto
(
struct
hci_proto
*
hp
)
{
int
err
=
0
;
BT_DBG
(
"%p name %s id %d"
,
hp
,
hp
->
name
,
hp
->
id
);
if
(
hp
->
id
>=
HCI_MAX_PROTO
)
return
-
EINVAL
;
mutex_lock
(
&
hci_task_lock
);
if
(
hci_proto
[
hp
->
id
])
hci_proto
[
hp
->
id
]
=
NULL
;
else
err
=
-
ENOENT
;
mutex_unlock
(
&
hci_task_lock
);
return
err
;
}
EXPORT_SYMBOL
(
hci_unregister_proto
);
int
hci_register_cb
(
struct
hci_cb
*
cb
)
int
hci_register_cb
(
struct
hci_cb
*
cb
)
{
{
BT_DBG
(
"%p name %s"
,
cb
,
cb
->
name
);
BT_DBG
(
"%p name %s"
,
cb
,
cb
->
name
);
write_lock
_bh
(
&
hci_cb_list_lock
);
write_lock
(
&
hci_cb_list_lock
);
list_add
(
&
cb
->
list
,
&
hci_cb_list
);
list_add
(
&
cb
->
list
,
&
hci_cb_list
);
write_unlock
_bh
(
&
hci_cb_list_lock
);
write_unlock
(
&
hci_cb_list_lock
);
return
0
;
return
0
;
}
}
...
@@ -1862,9 +1842,9 @@ int hci_unregister_cb(struct hci_cb *cb)
...
@@ -1862,9 +1842,9 @@ int hci_unregister_cb(struct hci_cb *cb)
{
{
BT_DBG
(
"%p name %s"
,
cb
,
cb
->
name
);
BT_DBG
(
"%p name %s"
,
cb
,
cb
->
name
);
write_lock
_bh
(
&
hci_cb_list_lock
);
write_lock
(
&
hci_cb_list_lock
);
list_del
(
&
cb
->
list
);
list_del
(
&
cb
->
list
);
write_unlock
_bh
(
&
hci_cb_list_lock
);
write_unlock
(
&
hci_cb_list_lock
);
return
0
;
return
0
;
}
}
...
@@ -1980,7 +1960,7 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
...
@@ -1980,7 +1960,7 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
skb_shinfo
(
skb
)
->
frag_list
=
NULL
;
skb_shinfo
(
skb
)
->
frag_list
=
NULL
;
/* Queue all fragments atomically */
/* Queue all fragments atomically */
spin_lock
_bh
(
&
queue
->
lock
);
spin_lock
(
&
queue
->
lock
);
__skb_queue_tail
(
queue
,
skb
);
__skb_queue_tail
(
queue
,
skb
);
...
@@ -1998,7 +1978,7 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
...
@@ -1998,7 +1978,7 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
__skb_queue_tail
(
queue
,
skb
);
__skb_queue_tail
(
queue
,
skb
);
}
while
(
list
);
}
while
(
list
);
spin_unlock
_bh
(
&
queue
->
lock
);
spin_unlock
(
&
queue
->
lock
);
}
}
}
}
...
@@ -2407,8 +2387,6 @@ static void hci_tx_work(struct work_struct *work)
...
@@ -2407,8 +2387,6 @@ static void hci_tx_work(struct work_struct *work)
struct
hci_dev
*
hdev
=
container_of
(
work
,
struct
hci_dev
,
tx_work
);
struct
hci_dev
*
hdev
=
container_of
(
work
,
struct
hci_dev
,
tx_work
);
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
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
);
...
@@ -2425,8 +2403,6 @@ static void hci_tx_work(struct work_struct *work)
...
@@ -2425,8 +2403,6 @@ static void hci_tx_work(struct work_struct *work)
/* Send next queued raw (unknown type) packet */
/* Send next queued raw (unknown type) packet */
while
((
skb
=
skb_dequeue
(
&
hdev
->
raw_q
)))
while
((
skb
=
skb_dequeue
(
&
hdev
->
raw_q
)))
hci_send_frame
(
skb
);
hci_send_frame
(
skb
);
mutex_unlock
(
&
hci_task_lock
);
}
}
/* ----- HCI RX task (incoming data processing) ----- */
/* ----- HCI RX task (incoming data processing) ----- */
...
@@ -2453,16 +2429,11 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -2453,16 +2429,11 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_unlock
(
hdev
);
hci_dev_unlock
(
hdev
);
if
(
conn
)
{
if
(
conn
)
{
register
struct
hci_proto
*
hp
;
hci_conn_enter_active_mode
(
conn
,
BT_POWER_FORCE_ACTIVE_OFF
);
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
];
l2cap_recv_acldata
(
conn
,
skb
,
flags
);
if
(
hp
&&
hp
->
recv_acldata
)
{
return
;
hp
->
recv_acldata
(
conn
,
skb
,
flags
);
return
;
}
}
else
{
}
else
{
BT_ERR
(
"%s ACL packet for unknown connection handle %d"
,
BT_ERR
(
"%s ACL packet for unknown connection handle %d"
,
hdev
->
name
,
handle
);
hdev
->
name
,
handle
);
...
@@ -2491,14 +2462,9 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
...
@@ -2491,14 +2462,9 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_unlock
(
hdev
);
hci_dev_unlock
(
hdev
);
if
(
conn
)
{
if
(
conn
)
{
register
struct
hci_proto
*
hp
;
/* Send to upper protocol */
/* Send to upper protocol */
hp
=
hci_proto
[
HCI_PROTO_SCO
];
sco_recv_scodata
(
conn
,
skb
);
if
(
hp
&&
hp
->
recv_scodata
)
{
return
;
hp
->
recv_scodata
(
conn
,
skb
);
return
;
}
}
else
{
}
else
{
BT_ERR
(
"%s SCO packet for unknown connection handle %d"
,
BT_ERR
(
"%s SCO packet for unknown connection handle %d"
,
hdev
->
name
,
handle
);
hdev
->
name
,
handle
);
...
@@ -2514,8 +2480,6 @@ static void hci_rx_work(struct work_struct *work)
...
@@ -2514,8 +2480,6 @@ static void hci_rx_work(struct work_struct *work)
BT_DBG
(
"%s"
,
hdev
->
name
);
BT_DBG
(
"%s"
,
hdev
->
name
);
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
))
{
/* Send copy to the sockets */
/* Send copy to the sockets */
...
@@ -2559,8 +2523,6 @@ static void hci_rx_work(struct work_struct *work)
...
@@ -2559,8 +2523,6 @@ static void hci_rx_work(struct work_struct *work)
break
;
break
;
}
}
}
}
mutex_unlock
(
&
hci_task_lock
);
}
}
static
void
hci_cmd_work
(
struct
work_struct
*
work
)
static
void
hci_cmd_work
(
struct
work_struct
*
work
)
...
...
net/bluetooth/hci_event.c
View file @
dc0d633e
...
@@ -556,6 +556,9 @@ static void hci_set_le_support(struct hci_dev *hdev)
...
@@ -556,6 +556,9 @@ static void hci_set_le_support(struct hci_dev *hdev)
static
void
hci_setup
(
struct
hci_dev
*
hdev
)
static
void
hci_setup
(
struct
hci_dev
*
hdev
)
{
{
if
(
hdev
->
dev_type
!=
HCI_BREDR
)
return
;
hci_setup_event_mask
(
hdev
);
hci_setup_event_mask
(
hdev
);
if
(
hdev
->
hci_ver
>
BLUETOOTH_VER_1_1
)
if
(
hdev
->
hci_ver
>
BLUETOOTH_VER_1_1
)
...
@@ -1030,7 +1033,8 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
...
@@ -1030,7 +1033,8 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
if
(
!
cp
)
if
(
!
cp
)
return
;
return
;
if
(
cp
->
enable
==
0x01
)
{
switch
(
cp
->
enable
)
{
case
LE_SCANNING_ENABLED
:
set_bit
(
HCI_LE_SCAN
,
&
hdev
->
dev_flags
);
set_bit
(
HCI_LE_SCAN
,
&
hdev
->
dev_flags
);
cancel_delayed_work_sync
(
&
hdev
->
adv_work
);
cancel_delayed_work_sync
(
&
hdev
->
adv_work
);
...
@@ -1038,12 +1042,19 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
...
@@ -1038,12 +1042,19 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
hci_dev_lock
(
hdev
);
hci_dev_lock
(
hdev
);
hci_adv_entries_clear
(
hdev
);
hci_adv_entries_clear
(
hdev
);
hci_dev_unlock
(
hdev
);
hci_dev_unlock
(
hdev
);
}
else
if
(
cp
->
enable
==
0x00
)
{
break
;
case
LE_SCANNING_DISABLED
:
clear_bit
(
HCI_LE_SCAN
,
&
hdev
->
dev_flags
);
clear_bit
(
HCI_LE_SCAN
,
&
hdev
->
dev_flags
);
cancel_delayed_work_sync
(
&
hdev
->
adv_work
);
cancel_delayed_work_sync
(
&
hdev
->
adv_work
);
queue_delayed_work
(
hdev
->
workqueue
,
&
hdev
->
adv_work
,
queue_delayed_work
(
hdev
->
workqueue
,
&
hdev
->
adv_work
,
jiffies
+
ADV_CLEAR_TIMEOUT
);
jiffies
+
ADV_CLEAR_TIMEOUT
);
break
;
default:
BT_ERR
(
"Used reserved LE_Scan_Enable param %d"
,
cp
->
enable
);
break
;
}
}
}
}
...
@@ -2253,24 +2264,29 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
...
@@ -2253,24 +2264,29 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
static
inline
void
hci_num_comp_pkts_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
static
inline
void
hci_num_comp_pkts_evt
(
struct
hci_dev
*
hdev
,
struct
sk_buff
*
skb
)
{
{
struct
hci_ev_num_comp_pkts
*
ev
=
(
void
*
)
skb
->
data
;
struct
hci_ev_num_comp_pkts
*
ev
=
(
void
*
)
skb
->
data
;
__le16
*
ptr
;
int
i
;
int
i
;
skb_pull
(
skb
,
sizeof
(
*
ev
));
skb_pull
(
skb
,
sizeof
(
*
ev
));
BT_DBG
(
"%s num_hndl %d"
,
hdev
->
name
,
ev
->
num_hndl
);
BT_DBG
(
"%s num_hndl %d"
,
hdev
->
name
,
ev
->
num_hndl
);
if
(
hdev
->
flow_ctl_mode
!=
HCI_FLOW_CTL_MODE_PACKET_BASED
)
{
BT_ERR
(
"Wrong event for mode %d"
,
hdev
->
flow_ctl_mode
);
return
;
}
if
(
skb
->
len
<
ev
->
num_hndl
*
4
)
{
if
(
skb
->
len
<
ev
->
num_hndl
*
4
)
{
BT_DBG
(
"%s bad parameters"
,
hdev
->
name
);
BT_DBG
(
"%s bad parameters"
,
hdev
->
name
);
return
;
return
;
}
}
for
(
i
=
0
,
ptr
=
(
__le16
*
)
skb
->
data
;
i
<
ev
->
num_hndl
;
i
++
)
{
for
(
i
=
0
;
i
<
ev
->
num_hndl
;
i
++
)
{
struct
hci_comp_pkts_info
*
info
=
&
ev
->
handles
[
i
];
struct
hci_conn
*
conn
;
struct
hci_conn
*
conn
;
__u16
handle
,
count
;
__u16
handle
,
count
;
handle
=
get_unaligned_le16
(
ptr
++
);
handle
=
__le16_to_cpu
(
info
->
handle
);
count
=
get_unaligned_le16
(
ptr
++
);
count
=
__le16_to_cpu
(
info
->
count
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
handle
);
conn
=
hci_conn_hash_lookup_handle
(
hdev
,
handle
);
if
(
!
conn
)
if
(
!
conn
)
...
...
net/bluetooth/hidp/Kconfig
View file @
dc0d633e
config BT_HIDP
config BT_HIDP
tristate "HIDP protocol support"
tristate "HIDP protocol support"
depends on BT &&
BT_L2CAP &&
INPUT && HID_SUPPORT
depends on BT && INPUT && HID_SUPPORT
select HID
select HID
help
help
HIDP (Human Interface Device Protocol) is a transport layer
HIDP (Human Interface Device Protocol) is a transport layer
...
...
net/bluetooth/l2cap_core.c
View file @
dc0d633e
...
@@ -77,17 +77,6 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
...
@@ -77,17 +77,6 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
/* ---- L2CAP channels ---- */
/* ---- L2CAP channels ---- */
static
inline
void
chan_hold
(
struct
l2cap_chan
*
c
)
{
atomic_inc
(
&
c
->
refcnt
);
}
static
inline
void
chan_put
(
struct
l2cap_chan
*
c
)
{
if
(
atomic_dec_and_test
(
&
c
->
refcnt
))
kfree
(
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
,
*
r
=
NULL
;
struct
l2cap_chan
*
c
,
*
r
=
NULL
;
...
@@ -228,20 +217,6 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
...
@@ -228,20 +217,6 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
return
0
;
return
0
;
}
}
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
);
cancel_delayed_work_sync
(
work
);
schedule_delayed_work
(
work
,
timeout
);
}
static
void
l2cap_clear_timer
(
struct
delayed_work
*
work
)
{
cancel_delayed_work_sync
(
work
);
}
static
char
*
state_to_string
(
int
state
)
static
char
*
state_to_string
(
int
state
)
{
{
switch
(
state
)
{
switch
(
state
)
{
...
@@ -301,7 +276,7 @@ static void l2cap_chan_timeout(struct work_struct *work)
...
@@ -301,7 +276,7 @@ static void l2cap_chan_timeout(struct work_struct *work)
release_sock
(
sk
);
release_sock
(
sk
);
chan
->
ops
->
close
(
chan
->
data
);
chan
->
ops
->
close
(
chan
->
data
);
chan_put
(
chan
);
l2cap_
chan_put
(
chan
);
}
}
struct
l2cap_chan
*
l2cap_chan_create
(
struct
sock
*
sk
)
struct
l2cap_chan
*
l2cap_chan_create
(
struct
sock
*
sk
)
...
@@ -335,7 +310,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan)
...
@@ -335,7 +310,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan)
list_del
(
&
chan
->
global_l
);
list_del
(
&
chan
->
global_l
);
write_unlock_bh
(
&
chan_list_lock
);
write_unlock_bh
(
&
chan_list_lock
);
chan_put
(
chan
);
l2cap_
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
)
...
@@ -377,7 +352,7 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
...
@@ -377,7 +352,7 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
chan
->
local_acc_lat
=
L2CAP_DEFAULT_ACC_LAT
;
chan
->
local_acc_lat
=
L2CAP_DEFAULT_ACC_LAT
;
chan
->
local_flush_to
=
L2CAP_DEFAULT_FLUSH_TO
;
chan
->
local_flush_to
=
L2CAP_DEFAULT_FLUSH_TO
;
chan_hold
(
chan
);
l2cap_
chan_hold
(
chan
);
list_add_rcu
(
&
chan
->
list
,
&
conn
->
chan_l
);
list_add_rcu
(
&
chan
->
list
,
&
conn
->
chan_l
);
}
}
...
@@ -399,7 +374,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
...
@@ -399,7 +374,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
list_del_rcu
(
&
chan
->
list
);
list_del_rcu
(
&
chan
->
list
);
synchronize_rcu
();
synchronize_rcu
();
chan_put
(
chan
);
l2cap_
chan_put
(
chan
);
chan
->
conn
=
NULL
;
chan
->
conn
=
NULL
;
hci_conn_put
(
conn
->
hcon
);
hci_conn_put
(
conn
->
hcon
);
...
@@ -713,7 +688,7 @@ static void l2cap_do_start(struct l2cap_chan *chan)
...
@@ -713,7 +688,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
);
schedule_delayed_work
(
&
conn
->
info_
work
,
schedule_delayed_work
(
&
conn
->
info_
timer
,
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
,
...
@@ -1010,7 +985,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
...
@@ -1010,7 +985,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
static
void
l2cap_info_timeout
(
struct
work_struct
*
work
)
static
void
l2cap_info_timeout
(
struct
work_struct
*
work
)
{
{
struct
l2cap_conn
*
conn
=
container_of
(
work
,
struct
l2cap_conn
,
struct
l2cap_conn
*
conn
=
container_of
(
work
,
struct
l2cap_conn
,
info_
work
.
work
);
info_
timer
.
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
;
...
@@ -1043,10 +1018,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
...
@@ -1043,10 +1018,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
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
)
cancel_delayed_work_sync
(
&
conn
->
info_work
);
__cancel_delayed_work
(
&
conn
->
info_timer
);
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
);
__cancel_delayed_work
(
&
conn
->
security_timer
);
smp_chan_destroy
(
conn
);
smp_chan_destroy
(
conn
);
}
}
...
@@ -1054,9 +1029,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
...
@@ -1054,9 +1029,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
kfree
(
conn
);
kfree
(
conn
);
}
}
static
void
security_timeout
(
unsigned
long
arg
)
static
void
security_timeout
(
struct
work_struct
*
work
)
{
{
struct
l2cap_conn
*
conn
=
(
void
*
)
arg
;
struct
l2cap_conn
*
conn
=
container_of
(
work
,
struct
l2cap_conn
,
security_timer
.
work
);
l2cap_conn_del
(
conn
->
hcon
,
ETIMEDOUT
);
l2cap_conn_del
(
conn
->
hcon
,
ETIMEDOUT
);
}
}
...
@@ -1100,10 +1076,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
...
@@ -1100,10 +1076,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
INIT_LIST_HEAD
(
&
conn
->
chan_l
);
INIT_LIST_HEAD
(
&
conn
->
chan_l
);
if
(
hcon
->
type
==
LE_LINK
)
if
(
hcon
->
type
==
LE_LINK
)
setup_timer
(
&
conn
->
security_timer
,
security_timeout
,
INIT_DELAYED_WORK
(
&
conn
->
security_timer
,
security_timeout
);
(
unsigned
long
)
conn
);
else
else
INIT_DELAYED_WORK
(
&
conn
->
info_
work
,
l2cap_info_timeout
);
INIT_DELAYED_WORK
(
&
conn
->
info_
timer
,
l2cap_info_timeout
);
conn
->
disc_reason
=
HCI_ERROR_REMOTE_USER_TERM
;
conn
->
disc_reason
=
HCI_ERROR_REMOTE_USER_TERM
;
...
@@ -2010,6 +1985,8 @@ static void l2cap_ack_timeout(struct work_struct *work)
...
@@ -2010,6 +1985,8 @@ static void l2cap_ack_timeout(struct work_struct *work)
struct
l2cap_chan
*
chan
=
container_of
(
work
,
struct
l2cap_chan
,
struct
l2cap_chan
*
chan
=
container_of
(
work
,
struct
l2cap_chan
,
ack_timer
.
work
);
ack_timer
.
work
);
BT_DBG
(
"chan %p"
,
chan
);
lock_sock
(
chan
->
sk
);
lock_sock
(
chan
->
sk
);
l2cap_send_ack
(
chan
);
l2cap_send_ack
(
chan
);
release_sock
(
chan
->
sk
);
release_sock
(
chan
->
sk
);
...
@@ -2597,7 +2574,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
...
@@ -2597,7 +2574,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
)
{
cancel_delayed_work_sync
(
&
conn
->
info_work
);
__cancel_delayed_work
(
&
conn
->
info_timer
);
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
;
...
@@ -2718,7 +2695,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
...
@@ -2718,7 +2695,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
);
schedule_delayed_work
(
&
conn
->
info_
work
,
schedule_delayed_work
(
&
conn
->
info_
timer
,
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
,
...
@@ -3143,7 +3120,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
...
@@ -3143,7 +3120,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
;
cancel_delayed_work_sync
(
&
conn
->
info_work
);
__cancel_delayed_work
(
&
conn
->
info_timer
);
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
;
...
@@ -4427,14 +4404,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
...
@@ -4427,14 +4404,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
/* ---- L2CAP interface with lower layer (HCI) ---- */
/* ---- L2CAP interface with lower layer (HCI) ---- */
static
int
l2cap_connect_ind
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
u8
type
)
int
l2cap_connect_ind
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
)
{
{
int
exact
=
0
,
lm1
=
0
,
lm2
=
0
;
int
exact
=
0
,
lm1
=
0
,
lm2
=
0
;
struct
l2cap_chan
*
c
;
struct
l2cap_chan
*
c
;
if
(
type
!=
ACL_LINK
)
return
-
EINVAL
;
BT_DBG
(
"hdev %s, bdaddr %s"
,
hdev
->
name
,
batostr
(
bdaddr
));
BT_DBG
(
"hdev %s, bdaddr %s"
,
hdev
->
name
,
batostr
(
bdaddr
));
/* Find listening sockets and check their link_mode */
/* Find listening sockets and check their link_mode */
...
@@ -4461,15 +4435,12 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
...
@@ -4461,15 +4435,12 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
return
exact
?
lm1
:
lm2
;
return
exact
?
lm1
:
lm2
;
}
}
static
int
l2cap_connect_cfm
(
struct
hci_conn
*
hcon
,
u8
status
)
int
l2cap_connect_cfm
(
struct
hci_conn
*
hcon
,
u8
status
)
{
{
struct
l2cap_conn
*
conn
;
struct
l2cap_conn
*
conn
;
BT_DBG
(
"hcon %p bdaddr %s status %d"
,
hcon
,
batostr
(
&
hcon
->
dst
),
status
);
BT_DBG
(
"hcon %p bdaddr %s status %d"
,
hcon
,
batostr
(
&
hcon
->
dst
),
status
);
if
(
!
(
hcon
->
type
==
ACL_LINK
||
hcon
->
type
==
LE_LINK
))
return
-
EINVAL
;
if
(
!
status
)
{
if
(
!
status
)
{
conn
=
l2cap_conn_add
(
hcon
,
status
);
conn
=
l2cap_conn_add
(
hcon
,
status
);
if
(
conn
)
if
(
conn
)
...
@@ -4480,27 +4451,22 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
...
@@ -4480,27 +4451,22 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
return
0
;
return
0
;
}
}
static
int
l2cap_disconn_ind
(
struct
hci_conn
*
hcon
)
int
l2cap_disconn_ind
(
struct
hci_conn
*
hcon
)
{
{
struct
l2cap_conn
*
conn
=
hcon
->
l2cap_data
;
struct
l2cap_conn
*
conn
=
hcon
->
l2cap_data
;
BT_DBG
(
"hcon %p"
,
hcon
);
BT_DBG
(
"hcon %p"
,
hcon
);
if
(
(
hcon
->
type
!=
ACL_LINK
&&
hcon
->
type
!=
LE_LINK
)
||
!
conn
)
if
(
!
conn
)
return
HCI_ERROR_REMOTE_USER_TERM
;
return
HCI_ERROR_REMOTE_USER_TERM
;
return
conn
->
disc_reason
;
return
conn
->
disc_reason
;
}
}
static
int
l2cap_disconn_cfm
(
struct
hci_conn
*
hcon
,
u8
reason
)
int
l2cap_disconn_cfm
(
struct
hci_conn
*
hcon
,
u8
reason
)
{
{
BT_DBG
(
"hcon %p reason %d"
,
hcon
,
reason
);
BT_DBG
(
"hcon %p reason %d"
,
hcon
,
reason
);
if
(
!
(
hcon
->
type
==
ACL_LINK
||
hcon
->
type
==
LE_LINK
))
return
-
EINVAL
;
l2cap_conn_del
(
hcon
,
bt_to_errno
(
reason
));
l2cap_conn_del
(
hcon
,
bt_to_errno
(
reason
));
return
0
;
return
0
;
}
}
...
@@ -4521,7 +4487,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
...
@@ -4521,7 +4487,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
}
}
}
}
static
int
l2cap_security_cfm
(
struct
hci_conn
*
hcon
,
u8
status
,
u8
encrypt
)
int
l2cap_security_cfm
(
struct
hci_conn
*
hcon
,
u8
status
,
u8
encrypt
)
{
{
struct
l2cap_conn
*
conn
=
hcon
->
l2cap_data
;
struct
l2cap_conn
*
conn
=
hcon
->
l2cap_data
;
struct
l2cap_chan
*
chan
;
struct
l2cap_chan
*
chan
;
...
@@ -4533,7 +4499,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
...
@@ -4533,7 +4499,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
if
(
hcon
->
type
==
LE_LINK
)
{
if
(
hcon
->
type
==
LE_LINK
)
{
smp_distribute_keys
(
conn
,
0
);
smp_distribute_keys
(
conn
,
0
);
del_timer
(
&
conn
->
security_timer
);
__cancel_delayed_work
(
&
conn
->
security_timer
);
}
}
rcu_read_lock
();
rcu_read_lock
();
...
@@ -4621,7 +4587,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
...
@@ -4621,7 +4587,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
return
0
;
return
0
;
}
}
static
int
l2cap_recv_acldata
(
struct
hci_conn
*
hcon
,
struct
sk_buff
*
skb
,
u16
flags
)
int
l2cap_recv_acldata
(
struct
hci_conn
*
hcon
,
struct
sk_buff
*
skb
,
u16
flags
)
{
{
struct
l2cap_conn
*
conn
=
hcon
->
l2cap_data
;
struct
l2cap_conn
*
conn
=
hcon
->
l2cap_data
;
...
@@ -4768,17 +4734,6 @@ static const struct file_operations l2cap_debugfs_fops = {
...
@@ -4768,17 +4734,6 @@ static const struct file_operations l2cap_debugfs_fops = {
static
struct
dentry
*
l2cap_debugfs
;
static
struct
dentry
*
l2cap_debugfs
;
static
struct
hci_proto
l2cap_hci_proto
=
{
.
name
=
"L2CAP"
,
.
id
=
HCI_PROTO_L2CAP
,
.
connect_ind
=
l2cap_connect_ind
,
.
connect_cfm
=
l2cap_connect_cfm
,
.
disconn_ind
=
l2cap_disconn_ind
,
.
disconn_cfm
=
l2cap_disconn_cfm
,
.
security_cfm
=
l2cap_security_cfm
,
.
recv_acldata
=
l2cap_recv_acldata
};
int
__init
l2cap_init
(
void
)
int
__init
l2cap_init
(
void
)
{
{
int
err
;
int
err
;
...
@@ -4787,13 +4742,6 @@ int __init l2cap_init(void)
...
@@ -4787,13 +4742,6 @@ int __init l2cap_init(void)
if
(
err
<
0
)
if
(
err
<
0
)
return
err
;
return
err
;
err
=
hci_register_proto
(
&
l2cap_hci_proto
);
if
(
err
<
0
)
{
BT_ERR
(
"L2CAP protocol registration failed"
);
bt_sock_unregister
(
BTPROTO_L2CAP
);
goto
error
;
}
if
(
bt_debugfs
)
{
if
(
bt_debugfs
)
{
l2cap_debugfs
=
debugfs_create_file
(
"l2cap"
,
0444
,
l2cap_debugfs
=
debugfs_create_file
(
"l2cap"
,
0444
,
bt_debugfs
,
NULL
,
&
l2cap_debugfs_fops
);
bt_debugfs
,
NULL
,
&
l2cap_debugfs_fops
);
...
@@ -4802,19 +4750,11 @@ int __init l2cap_init(void)
...
@@ -4802,19 +4750,11 @@ int __init l2cap_init(void)
}
}
return
0
;
return
0
;
error:
l2cap_cleanup_sockets
();
return
err
;
}
}
void
l2cap_exit
(
void
)
void
l2cap_exit
(
void
)
{
{
debugfs_remove
(
l2cap_debugfs
);
debugfs_remove
(
l2cap_debugfs
);
if
(
hci_unregister_proto
(
&
l2cap_hci_proto
)
<
0
)
BT_ERR
(
"L2CAP protocol unregistration failed"
);
l2cap_cleanup_sockets
();
l2cap_cleanup_sockets
();
}
}
...
...
net/bluetooth/mgmt.c
View file @
dc0d633e
...
@@ -30,6 +30,7 @@
...
@@ -30,6 +30,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/mgmt.h>
#include <net/bluetooth/mgmt.h>
#include <net/bluetooth/smp.h>
#define MGMT_VERSION 0
#define MGMT_VERSION 0
#define MGMT_REVISION 1
#define MGMT_REVISION 1
...
@@ -1642,8 +1643,15 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
...
@@ -1642,8 +1643,15 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
}
}
/* Continue with pairing via SMP */
/* Continue with pairing via SMP */
err
=
smp_user_confirm_reply
(
conn
,
mgmt_op
,
passkey
);
if
(
!
err
)
err
=
cmd_status
(
sk
,
index
,
mgmt_op
,
MGMT_STATUS_SUCCESS
);
else
err
=
cmd_status
(
sk
,
index
,
mgmt_op
,
MGMT_STATUS_FAILED
);
err
=
cmd_status
(
sk
,
index
,
mgmt_op
,
MGMT_STATUS_SUCCESS
);
goto
done
;
goto
done
;
}
}
...
...
net/bluetooth/rfcomm/Kconfig
View file @
dc0d633e
config BT_RFCOMM
config BT_RFCOMM
tristate "RFCOMM protocol support"
tristate "RFCOMM protocol support"
depends on BT
&& BT_L2CAP
depends on BT
help
help
RFCOMM provides connection oriented stream transport. RFCOMM
RFCOMM provides connection oriented stream transport. RFCOMM
support is required for Dialup Networking, OBEX and other Bluetooth
support is required for Dialup Networking, OBEX and other Bluetooth
...
...
net/bluetooth/rfcomm/core.c
View file @
dc0d633e
...
@@ -65,8 +65,7 @@ static DEFINE_MUTEX(rfcomm_mutex);
...
@@ -65,8 +65,7 @@ static DEFINE_MUTEX(rfcomm_mutex);
static
LIST_HEAD
(
session_list
);
static
LIST_HEAD
(
session_list
);
static
int
rfcomm_send_frame
(
struct
rfcomm_session
*
s
,
u8
*
data
,
int
len
,
static
int
rfcomm_send_frame
(
struct
rfcomm_session
*
s
,
u8
*
data
,
int
len
);
u32
priority
);
static
int
rfcomm_send_sabm
(
struct
rfcomm_session
*
s
,
u8
dlci
);
static
int
rfcomm_send_sabm
(
struct
rfcomm_session
*
s
,
u8
dlci
);
static
int
rfcomm_send_disc
(
struct
rfcomm_session
*
s
,
u8
dlci
);
static
int
rfcomm_send_disc
(
struct
rfcomm_session
*
s
,
u8
dlci
);
static
int
rfcomm_queue_disc
(
struct
rfcomm_dlc
*
d
);
static
int
rfcomm_queue_disc
(
struct
rfcomm_dlc
*
d
);
...
@@ -748,32 +747,23 @@ void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *d
...
@@ -748,32 +747,23 @@ void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *d
}
}
/* ---- RFCOMM frame sending ---- */
/* ---- RFCOMM frame sending ---- */
static
int
rfcomm_send_frame
(
struct
rfcomm_session
*
s
,
u8
*
data
,
int
len
,
static
int
rfcomm_send_frame
(
struct
rfcomm_session
*
s
,
u8
*
data
,
int
len
)
u32
priority
)
{
{
struct
socket
*
sock
=
s
->
sock
;
struct
sock
*
sk
=
sock
->
sk
;
struct
kvec
iv
=
{
data
,
len
};
struct
kvec
iv
=
{
data
,
len
};
struct
msghdr
msg
;
struct
msghdr
msg
;
BT_DBG
(
"session %p len %d priority %u"
,
s
,
len
,
priority
);
BT_DBG
(
"session %p len %d"
,
s
,
len
);
if
(
sk
->
sk_priority
!=
priority
)
{
lock_sock
(
sk
);
sk
->
sk_priority
=
priority
;
release_sock
(
sk
);
}
memset
(
&
msg
,
0
,
sizeof
(
msg
));
memset
(
&
msg
,
0
,
sizeof
(
msg
));
return
kernel_sendmsg
(
sock
,
&
msg
,
&
iv
,
1
,
len
);
return
kernel_sendmsg
(
s
->
s
ock
,
&
msg
,
&
iv
,
1
,
len
);
}
}
static
int
rfcomm_send_cmd
(
struct
rfcomm_session
*
s
,
struct
rfcomm_cmd
*
cmd
)
static
int
rfcomm_send_cmd
(
struct
rfcomm_session
*
s
,
struct
rfcomm_cmd
*
cmd
)
{
{
BT_DBG
(
"%p cmd %u"
,
s
,
cmd
->
ctrl
);
BT_DBG
(
"%p cmd %u"
,
s
,
cmd
->
ctrl
);
return
rfcomm_send_frame
(
s
,
(
void
*
)
cmd
,
sizeof
(
*
cmd
)
,
HCI_PRIO_MAX
);
return
rfcomm_send_frame
(
s
,
(
void
*
)
cmd
,
sizeof
(
*
cmd
));
}
}
static
int
rfcomm_send_sabm
(
struct
rfcomm_session
*
s
,
u8
dlci
)
static
int
rfcomm_send_sabm
(
struct
rfcomm_session
*
s
,
u8
dlci
)
...
@@ -829,8 +819,6 @@ static int rfcomm_queue_disc(struct rfcomm_dlc *d)
...
@@ -829,8 +819,6 @@ static int rfcomm_queue_disc(struct rfcomm_dlc *d)
if
(
!
skb
)
if
(
!
skb
)
return
-
ENOMEM
;
return
-
ENOMEM
;
skb
->
priority
=
HCI_PRIO_MAX
;
cmd
=
(
void
*
)
__skb_put
(
skb
,
sizeof
(
*
cmd
));
cmd
=
(
void
*
)
__skb_put
(
skb
,
sizeof
(
*
cmd
));
cmd
->
addr
=
d
->
addr
;
cmd
->
addr
=
d
->
addr
;
cmd
->
ctrl
=
__ctrl
(
RFCOMM_DISC
,
1
);
cmd
->
ctrl
=
__ctrl
(
RFCOMM_DISC
,
1
);
...
@@ -878,7 +866,7 @@ static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
...
@@ -878,7 +866,7 @@ static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
*
ptr
=
__fcs
(
buf
);
ptr
++
;
*
ptr
=
__fcs
(
buf
);
ptr
++
;
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
,
HCI_PRIO_MAX
);
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
);
}
}
static
int
rfcomm_send_pn
(
struct
rfcomm_session
*
s
,
int
cr
,
struct
rfcomm_dlc
*
d
)
static
int
rfcomm_send_pn
(
struct
rfcomm_session
*
s
,
int
cr
,
struct
rfcomm_dlc
*
d
)
...
@@ -920,7 +908,7 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
...
@@ -920,7 +908,7 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
*
ptr
=
__fcs
(
buf
);
ptr
++
;
*
ptr
=
__fcs
(
buf
);
ptr
++
;
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
,
HCI_PRIO_MAX
);
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
);
}
}
int
rfcomm_send_rpn
(
struct
rfcomm_session
*
s
,
int
cr
,
u8
dlci
,
int
rfcomm_send_rpn
(
struct
rfcomm_session
*
s
,
int
cr
,
u8
dlci
,
...
@@ -958,7 +946,7 @@ int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
...
@@ -958,7 +946,7 @@ int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
*
ptr
=
__fcs
(
buf
);
ptr
++
;
*
ptr
=
__fcs
(
buf
);
ptr
++
;
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
,
HCI_PRIO_MAX
);
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
);
}
}
static
int
rfcomm_send_rls
(
struct
rfcomm_session
*
s
,
int
cr
,
u8
dlci
,
u8
status
)
static
int
rfcomm_send_rls
(
struct
rfcomm_session
*
s
,
int
cr
,
u8
dlci
,
u8
status
)
...
@@ -985,7 +973,7 @@ static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
...
@@ -985,7 +973,7 @@ static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
*
ptr
=
__fcs
(
buf
);
ptr
++
;
*
ptr
=
__fcs
(
buf
);
ptr
++
;
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
,
HCI_PRIO_MAX
);
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
);
}
}
static
int
rfcomm_send_msc
(
struct
rfcomm_session
*
s
,
int
cr
,
u8
dlci
,
u8
v24_sig
)
static
int
rfcomm_send_msc
(
struct
rfcomm_session
*
s
,
int
cr
,
u8
dlci
,
u8
v24_sig
)
...
@@ -1012,7 +1000,7 @@ static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig
...
@@ -1012,7 +1000,7 @@ static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig
*
ptr
=
__fcs
(
buf
);
ptr
++
;
*
ptr
=
__fcs
(
buf
);
ptr
++
;
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
,
HCI_PRIO_MAX
);
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
);
}
}
static
int
rfcomm_send_fcoff
(
struct
rfcomm_session
*
s
,
int
cr
)
static
int
rfcomm_send_fcoff
(
struct
rfcomm_session
*
s
,
int
cr
)
...
@@ -1034,7 +1022,7 @@ static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
...
@@ -1034,7 +1022,7 @@ static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
*
ptr
=
__fcs
(
buf
);
ptr
++
;
*
ptr
=
__fcs
(
buf
);
ptr
++
;
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
,
HCI_PRIO_MAX
);
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
);
}
}
static
int
rfcomm_send_fcon
(
struct
rfcomm_session
*
s
,
int
cr
)
static
int
rfcomm_send_fcon
(
struct
rfcomm_session
*
s
,
int
cr
)
...
@@ -1056,7 +1044,7 @@ static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
...
@@ -1056,7 +1044,7 @@ static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
*
ptr
=
__fcs
(
buf
);
ptr
++
;
*
ptr
=
__fcs
(
buf
);
ptr
++
;
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
,
HCI_PRIO_MAX
);
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
);
}
}
static
int
rfcomm_send_test
(
struct
rfcomm_session
*
s
,
int
cr
,
u8
*
pattern
,
int
len
)
static
int
rfcomm_send_test
(
struct
rfcomm_session
*
s
,
int
cr
,
u8
*
pattern
,
int
len
)
...
@@ -1107,7 +1095,7 @@ static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
...
@@ -1107,7 +1095,7 @@ static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
*
ptr
=
__fcs
(
buf
);
ptr
++
;
*
ptr
=
__fcs
(
buf
);
ptr
++
;
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
,
HCI_PRIO_MAX
);
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
);
}
}
static
void
rfcomm_make_uih
(
struct
sk_buff
*
skb
,
u8
addr
)
static
void
rfcomm_make_uih
(
struct
sk_buff
*
skb
,
u8
addr
)
...
@@ -1786,8 +1774,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
...
@@ -1786,8 +1774,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
return
skb_queue_len
(
&
d
->
tx_queue
);
return
skb_queue_len
(
&
d
->
tx_queue
);
while
(
d
->
tx_credits
&&
(
skb
=
skb_dequeue
(
&
d
->
tx_queue
)))
{
while
(
d
->
tx_credits
&&
(
skb
=
skb_dequeue
(
&
d
->
tx_queue
)))
{
err
=
rfcomm_send_frame
(
d
->
session
,
skb
->
data
,
skb
->
len
,
err
=
rfcomm_send_frame
(
d
->
session
,
skb
->
data
,
skb
->
len
);
skb
->
priority
);
if
(
err
<
0
)
{
if
(
err
<
0
)
{
skb_queue_head
(
&
d
->
tx_queue
,
skb
);
skb_queue_head
(
&
d
->
tx_queue
,
skb
);
break
;
break
;
...
...
net/bluetooth/sco.c
View file @
dc0d633e
...
@@ -893,15 +893,12 @@ static void sco_conn_ready(struct sco_conn *conn)
...
@@ -893,15 +893,12 @@ static void sco_conn_ready(struct sco_conn *conn)
}
}
/* ----- SCO interface with lower layer (HCI) ----- */
/* ----- SCO interface with lower layer (HCI) ----- */
static
int
sco_connect_ind
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
,
__u8
type
)
int
sco_connect_ind
(
struct
hci_dev
*
hdev
,
bdaddr_t
*
bdaddr
)
{
{
register
struct
sock
*
sk
;
register
struct
sock
*
sk
;
struct
hlist_node
*
node
;
struct
hlist_node
*
node
;
int
lm
=
0
;
int
lm
=
0
;
if
(
type
!=
SCO_LINK
&&
type
!=
ESCO_LINK
)
return
-
EINVAL
;
BT_DBG
(
"hdev %s, bdaddr %s"
,
hdev
->
name
,
batostr
(
bdaddr
));
BT_DBG
(
"hdev %s, bdaddr %s"
,
hdev
->
name
,
batostr
(
bdaddr
));
/* Find listening sockets */
/* Find listening sockets */
...
@@ -921,13 +918,9 @@ static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
...
@@ -921,13 +918,9 @@ static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
return
lm
;
return
lm
;
}
}
static
int
sco_connect_cfm
(
struct
hci_conn
*
hcon
,
__u8
status
)
int
sco_connect_cfm
(
struct
hci_conn
*
hcon
,
__u8
status
)
{
{
BT_DBG
(
"hcon %p bdaddr %s status %d"
,
hcon
,
batostr
(
&
hcon
->
dst
),
status
);
BT_DBG
(
"hcon %p bdaddr %s status %d"
,
hcon
,
batostr
(
&
hcon
->
dst
),
status
);
if
(
hcon
->
type
!=
SCO_LINK
&&
hcon
->
type
!=
ESCO_LINK
)
return
-
EINVAL
;
if
(
!
status
)
{
if
(
!
status
)
{
struct
sco_conn
*
conn
;
struct
sco_conn
*
conn
;
...
@@ -940,19 +933,15 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
...
@@ -940,19 +933,15 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
return
0
;
return
0
;
}
}
static
int
sco_disconn_cfm
(
struct
hci_conn
*
hcon
,
__u8
reason
)
int
sco_disconn_cfm
(
struct
hci_conn
*
hcon
,
__u8
reason
)
{
{
BT_DBG
(
"hcon %p reason %d"
,
hcon
,
reason
);
BT_DBG
(
"hcon %p reason %d"
,
hcon
,
reason
);
if
(
hcon
->
type
!=
SCO_LINK
&&
hcon
->
type
!=
ESCO_LINK
)
return
-
EINVAL
;
sco_conn_del
(
hcon
,
bt_to_errno
(
reason
));
sco_conn_del
(
hcon
,
bt_to_errno
(
reason
));
return
0
;
return
0
;
}
}
static
int
sco_recv_scodata
(
struct
hci_conn
*
hcon
,
struct
sk_buff
*
skb
)
int
sco_recv_scodata
(
struct
hci_conn
*
hcon
,
struct
sk_buff
*
skb
)
{
{
struct
sco_conn
*
conn
=
hcon
->
sco_data
;
struct
sco_conn
*
conn
=
hcon
->
sco_data
;
...
@@ -1028,15 +1017,6 @@ static const struct net_proto_family sco_sock_family_ops = {
...
@@ -1028,15 +1017,6 @@ static const struct net_proto_family sco_sock_family_ops = {
.
create
=
sco_sock_create
,
.
create
=
sco_sock_create
,
};
};
static
struct
hci_proto
sco_hci_proto
=
{
.
name
=
"SCO"
,
.
id
=
HCI_PROTO_SCO
,
.
connect_ind
=
sco_connect_ind
,
.
connect_cfm
=
sco_connect_cfm
,
.
disconn_cfm
=
sco_disconn_cfm
,
.
recv_scodata
=
sco_recv_scodata
};
int
__init
sco_init
(
void
)
int
__init
sco_init
(
void
)
{
{
int
err
;
int
err
;
...
@@ -1051,13 +1031,6 @@ int __init sco_init(void)
...
@@ -1051,13 +1031,6 @@ int __init sco_init(void)
goto
error
;
goto
error
;
}
}
err
=
hci_register_proto
(
&
sco_hci_proto
);
if
(
err
<
0
)
{
BT_ERR
(
"SCO protocol registration failed"
);
bt_sock_unregister
(
BTPROTO_SCO
);
goto
error
;
}
if
(
bt_debugfs
)
{
if
(
bt_debugfs
)
{
sco_debugfs
=
debugfs_create_file
(
"sco"
,
0444
,
sco_debugfs
=
debugfs_create_file
(
"sco"
,
0444
,
bt_debugfs
,
NULL
,
&
sco_debugfs_fops
);
bt_debugfs
,
NULL
,
&
sco_debugfs_fops
);
...
@@ -1081,9 +1054,6 @@ void __exit sco_exit(void)
...
@@ -1081,9 +1054,6 @@ void __exit sco_exit(void)
if
(
bt_sock_unregister
(
BTPROTO_SCO
)
<
0
)
if
(
bt_sock_unregister
(
BTPROTO_SCO
)
<
0
)
BT_ERR
(
"SCO socket unregistration failed"
);
BT_ERR
(
"SCO socket unregistration failed"
);
if
(
hci_unregister_proto
(
&
sco_hci_proto
)
<
0
)
BT_ERR
(
"SCO protocol unregistration failed"
);
proto_unregister
(
&
sco_proto
);
proto_unregister
(
&
sco_proto
);
}
}
...
...
net/bluetooth/smp.c
View file @
dc0d633e
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/mgmt.h>
#include <net/bluetooth/smp.h>
#include <net/bluetooth/smp.h>
#include <linux/crypto.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <linux/scatterlist.h>
...
@@ -184,28 +185,50 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
...
@@ -184,28 +185,50 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
skb
->
priority
=
HCI_PRIO_MAX
;
skb
->
priority
=
HCI_PRIO_MAX
;
hci_send_acl
(
conn
->
hchan
,
skb
,
0
);
hci_send_acl
(
conn
->
hchan
,
skb
,
0
);
mod_timer
(
&
conn
->
security_timer
,
jiffies
+
cancel_delayed_work_sync
(
&
conn
->
security_timer
);
schedule_delayed_work
(
&
conn
->
security_timer
,
msecs_to_jiffies
(
SMP_TIMEOUT
));
msecs_to_jiffies
(
SMP_TIMEOUT
));
}
}
static
__u8
authreq_to_seclevel
(
__u8
authreq
)
{
if
(
authreq
&
SMP_AUTH_MITM
)
return
BT_SECURITY_HIGH
;
else
return
BT_SECURITY_MEDIUM
;
}
static
__u8
seclevel_to_authreq
(
__u8
sec_level
)
{
switch
(
sec_level
)
{
case
BT_SECURITY_HIGH
:
return
SMP_AUTH_MITM
|
SMP_AUTH_BONDING
;
case
BT_SECURITY_MEDIUM
:
return
SMP_AUTH_BONDING
;
default:
return
SMP_AUTH_NONE
;
}
}
static
void
build_pairing_cmd
(
struct
l2cap_conn
*
conn
,
static
void
build_pairing_cmd
(
struct
l2cap_conn
*
conn
,
struct
smp_cmd_pairing
*
req
,
struct
smp_cmd_pairing
*
req
,
struct
smp_cmd_pairing
*
rsp
,
struct
smp_cmd_pairing
*
rsp
,
__u8
authreq
)
__u8
authreq
)
{
{
u8
dist_keys
;
u8
dist_keys
=
0
;
dist_keys
=
0
;
if
(
test_bit
(
HCI_PAIRABLE
,
&
conn
->
hcon
->
hdev
->
flags
))
{
if
(
test_bit
(
HCI_PAIRABLE
,
&
conn
->
hcon
->
hdev
->
flags
))
{
dist_keys
=
SMP_DIST_ENC_KEY
;
dist_keys
=
SMP_DIST_ENC_KEY
;
authreq
|=
SMP_AUTH_BONDING
;
authreq
|=
SMP_AUTH_BONDING
;
}
else
{
authreq
&=
~
SMP_AUTH_BONDING
;
}
}
if
(
rsp
==
NULL
)
{
if
(
rsp
==
NULL
)
{
req
->
io_capability
=
conn
->
hcon
->
io_capability
;
req
->
io_capability
=
conn
->
hcon
->
io_capability
;
req
->
oob_flag
=
SMP_OOB_NOT_PRESENT
;
req
->
oob_flag
=
SMP_OOB_NOT_PRESENT
;
req
->
max_key_size
=
SMP_MAX_ENC_KEY_SIZE
;
req
->
max_key_size
=
SMP_MAX_ENC_KEY_SIZE
;
req
->
init_key_dist
=
dist_keys
;
req
->
init_key_dist
=
0
;
req
->
resp_key_dist
=
dist_keys
;
req
->
resp_key_dist
=
dist_keys
;
req
->
auth_req
=
authreq
;
req
->
auth_req
=
authreq
;
return
;
return
;
...
@@ -214,7 +237,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
...
@@ -214,7 +237,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
rsp
->
io_capability
=
conn
->
hcon
->
io_capability
;
rsp
->
io_capability
=
conn
->
hcon
->
io_capability
;
rsp
->
oob_flag
=
SMP_OOB_NOT_PRESENT
;
rsp
->
oob_flag
=
SMP_OOB_NOT_PRESENT
;
rsp
->
max_key_size
=
SMP_MAX_ENC_KEY_SIZE
;
rsp
->
max_key_size
=
SMP_MAX_ENC_KEY_SIZE
;
rsp
->
init_key_dist
=
req
->
init_key_dist
&
dist_keys
;
rsp
->
init_key_dist
=
0
;
rsp
->
resp_key_dist
=
req
->
resp_key_dist
&
dist_keys
;
rsp
->
resp_key_dist
=
req
->
resp_key_dist
&
dist_keys
;
rsp
->
auth_req
=
authreq
;
rsp
->
auth_req
=
authreq
;
}
}
...
@@ -240,10 +263,99 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
...
@@ -240,10 +263,99 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
clear_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
hcon
->
pend
);
clear_bit
(
HCI_CONN_ENCRYPT_PEND
,
&
conn
->
hcon
->
pend
);
mgmt_auth_failed
(
conn
->
hcon
->
hdev
,
conn
->
dst
,
reason
);
mgmt_auth_failed
(
conn
->
hcon
->
hdev
,
conn
->
dst
,
reason
);
del_timer
(
&
conn
->
security_timer
);
cancel_delayed_work_sync
(
&
conn
->
security_timer
);
smp_chan_destroy
(
conn
);
smp_chan_destroy
(
conn
);
}
}
#define JUST_WORKS 0x00
#define JUST_CFM 0x01
#define REQ_PASSKEY 0x02
#define CFM_PASSKEY 0x03
#define REQ_OOB 0x04
#define OVERLAP 0xFF
static
const
u8
gen_method
[
5
][
5
]
=
{
{
JUST_WORKS
,
JUST_CFM
,
REQ_PASSKEY
,
JUST_WORKS
,
REQ_PASSKEY
},
{
JUST_WORKS
,
JUST_CFM
,
REQ_PASSKEY
,
JUST_WORKS
,
REQ_PASSKEY
},
{
CFM_PASSKEY
,
CFM_PASSKEY
,
REQ_PASSKEY
,
JUST_WORKS
,
CFM_PASSKEY
},
{
JUST_WORKS
,
JUST_CFM
,
JUST_WORKS
,
JUST_WORKS
,
JUST_CFM
},
{
CFM_PASSKEY
,
CFM_PASSKEY
,
REQ_PASSKEY
,
JUST_WORKS
,
OVERLAP
},
};
static
int
tk_request
(
struct
l2cap_conn
*
conn
,
u8
remote_oob
,
u8
auth
,
u8
local_io
,
u8
remote_io
)
{
struct
hci_conn
*
hcon
=
conn
->
hcon
;
struct
smp_chan
*
smp
=
conn
->
smp_chan
;
u8
method
;
u32
passkey
=
0
;
int
ret
=
0
;
/* Initialize key for JUST WORKS */
memset
(
smp
->
tk
,
0
,
sizeof
(
smp
->
tk
));
clear_bit
(
SMP_FLAG_TK_VALID
,
&
smp
->
smp_flags
);
BT_DBG
(
"tk_request: auth:%d lcl:%d rem:%d"
,
auth
,
local_io
,
remote_io
);
/* If neither side wants MITM, use JUST WORKS */
/* If either side has unknown io_caps, use JUST WORKS */
/* Otherwise, look up method from the table */
if
(
!
(
auth
&
SMP_AUTH_MITM
)
||
local_io
>
SMP_IO_KEYBOARD_DISPLAY
||
remote_io
>
SMP_IO_KEYBOARD_DISPLAY
)
method
=
JUST_WORKS
;
else
method
=
gen_method
[
local_io
][
remote_io
];
/* If not bonding, don't ask user to confirm a Zero TK */
if
(
!
(
auth
&
SMP_AUTH_BONDING
)
&&
method
==
JUST_CFM
)
method
=
JUST_WORKS
;
/* If Just Works, Continue with Zero TK */
if
(
method
==
JUST_WORKS
)
{
set_bit
(
SMP_FLAG_TK_VALID
,
&
smp
->
smp_flags
);
return
0
;
}
/* Not Just Works/Confirm results in MITM Authentication */
if
(
method
!=
JUST_CFM
)
set_bit
(
SMP_FLAG_MITM_AUTH
,
&
smp
->
smp_flags
);
/* If both devices have Keyoard-Display I/O, the master
* Confirms and the slave Enters the passkey.
*/
if
(
method
==
OVERLAP
)
{
if
(
hcon
->
link_mode
&
HCI_LM_MASTER
)
method
=
CFM_PASSKEY
;
else
method
=
REQ_PASSKEY
;
}
/* Generate random passkey. Not valid until confirmed. */
if
(
method
==
CFM_PASSKEY
)
{
u8
key
[
16
];
memset
(
key
,
0
,
sizeof
(
key
));
get_random_bytes
(
&
passkey
,
sizeof
(
passkey
));
passkey
%=
1000000
;
put_unaligned_le32
(
passkey
,
key
);
swap128
(
key
,
smp
->
tk
);
BT_DBG
(
"PassKey: %d"
,
passkey
);
}
hci_dev_lock
(
hcon
->
hdev
);
if
(
method
==
REQ_PASSKEY
)
ret
=
mgmt_user_passkey_request
(
hcon
->
hdev
,
conn
->
dst
);
else
ret
=
mgmt_user_confirm_request
(
hcon
->
hdev
,
conn
->
dst
,
cpu_to_le32
(
passkey
),
0
);
hci_dev_unlock
(
hcon
->
hdev
);
return
ret
;
}
static
void
confirm_work
(
struct
work_struct
*
work
)
static
void
confirm_work
(
struct
work_struct
*
work
)
{
{
struct
smp_chan
*
smp
=
container_of
(
work
,
struct
smp_chan
,
confirm
);
struct
smp_chan
*
smp
=
container_of
(
work
,
struct
smp_chan
,
confirm
);
...
@@ -276,6 +388,8 @@ static void confirm_work(struct work_struct *work)
...
@@ -276,6 +388,8 @@ static void confirm_work(struct work_struct *work)
goto
error
;
goto
error
;
}
}
clear_bit
(
SMP_FLAG_CFM_PENDING
,
&
smp
->
smp_flags
);
swap128
(
res
,
cp
.
confirm_val
);
swap128
(
res
,
cp
.
confirm_val
);
smp_send_cmd
(
smp
->
conn
,
SMP_CMD_PAIRING_CONFIRM
,
sizeof
(
cp
),
&
cp
);
smp_send_cmd
(
smp
->
conn
,
SMP_CMD_PAIRING_CONFIRM
,
sizeof
(
cp
),
&
cp
);
...
@@ -381,6 +495,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
...
@@ -381,6 +495,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
smp
->
conn
=
conn
;
smp
->
conn
=
conn
;
conn
->
smp_chan
=
smp
;
conn
->
smp_chan
=
smp
;
conn
->
hcon
->
smp_conn
=
conn
;
hci_conn_hold
(
conn
->
hcon
);
hci_conn_hold
(
conn
->
hcon
);
...
@@ -398,18 +513,64 @@ void smp_chan_destroy(struct l2cap_conn *conn)
...
@@ -398,18 +513,64 @@ void smp_chan_destroy(struct l2cap_conn *conn)
kfree
(
smp
);
kfree
(
smp
);
conn
->
smp_chan
=
NULL
;
conn
->
smp_chan
=
NULL
;
conn
->
hcon
->
smp_conn
=
NULL
;
hci_conn_put
(
conn
->
hcon
);
hci_conn_put
(
conn
->
hcon
);
}
}
int
smp_user_confirm_reply
(
struct
hci_conn
*
hcon
,
u16
mgmt_op
,
__le32
passkey
)
{
struct
l2cap_conn
*
conn
=
hcon
->
smp_conn
;
struct
smp_chan
*
smp
;
u32
value
;
u8
key
[
16
];
BT_DBG
(
""
);
if
(
!
conn
)
return
-
ENOTCONN
;
smp
=
conn
->
smp_chan
;
switch
(
mgmt_op
)
{
case
MGMT_OP_USER_PASSKEY_REPLY
:
value
=
le32_to_cpu
(
passkey
);
memset
(
key
,
0
,
sizeof
(
key
));
BT_DBG
(
"PassKey: %d"
,
value
);
put_unaligned_le32
(
value
,
key
);
swap128
(
key
,
smp
->
tk
);
/* Fall Through */
case
MGMT_OP_USER_CONFIRM_REPLY
:
set_bit
(
SMP_FLAG_TK_VALID
,
&
smp
->
smp_flags
);
break
;
case
MGMT_OP_USER_PASSKEY_NEG_REPLY
:
case
MGMT_OP_USER_CONFIRM_NEG_REPLY
:
smp_failure
(
conn
,
SMP_PASSKEY_ENTRY_FAILED
,
1
);
return
0
;
default:
smp_failure
(
conn
,
SMP_PASSKEY_ENTRY_FAILED
,
1
);
return
-
EOPNOTSUPP
;
}
/* If it is our turn to send Pairing Confirm, do so now */
if
(
test_bit
(
SMP_FLAG_CFM_PENDING
,
&
smp
->
smp_flags
))
queue_work
(
hcon
->
hdev
->
workqueue
,
&
smp
->
confirm
);
return
0
;
}
static
u8
smp_cmd_pairing_req
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
static
u8
smp_cmd_pairing_req
(
struct
l2cap_conn
*
conn
,
struct
sk_buff
*
skb
)
{
{
struct
smp_cmd_pairing
rsp
,
*
req
=
(
void
*
)
skb
->
data
;
struct
smp_cmd_pairing
rsp
,
*
req
=
(
void
*
)
skb
->
data
;
struct
smp_chan
*
smp
;
struct
smp_chan
*
smp
;
u8
key_size
;
u8
key_size
;
u8
auth
=
SMP_AUTH_NONE
;
int
ret
;
int
ret
;
BT_DBG
(
"conn %p"
,
conn
);
BT_DBG
(
"conn %p"
,
conn
);
if
(
conn
->
hcon
->
link_mode
&
HCI_LM_MASTER
)
return
SMP_CMD_NOTSUPP
;
if
(
!
test_and_set_bit
(
HCI_CONN_LE_SMP_PEND
,
&
conn
->
hcon
->
pend
))
if
(
!
test_and_set_bit
(
HCI_CONN_LE_SMP_PEND
,
&
conn
->
hcon
->
pend
))
smp
=
smp_chan_create
(
conn
);
smp
=
smp_chan_create
(
conn
);
...
@@ -419,19 +580,16 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
...
@@ -419,19 +580,16 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
memcpy
(
&
smp
->
preq
[
1
],
req
,
sizeof
(
*
req
));
memcpy
(
&
smp
->
preq
[
1
],
req
,
sizeof
(
*
req
));
skb_pull
(
skb
,
sizeof
(
*
req
));
skb_pull
(
skb
,
sizeof
(
*
req
));
if
(
req
->
oob_flag
)
/* We didn't start the pairing, so match remote */
return
SMP_OOB_NOT_AVAIL
;
if
(
req
->
auth_req
&
SMP_AUTH_BONDING
)
auth
=
req
->
auth_req
;
/* We didn't start the pairing, so no requirements */
build_pairing_cmd
(
conn
,
req
,
&
rsp
,
auth
);
build_pairing_cmd
(
conn
,
req
,
&
rsp
,
SMP_AUTH_NONE
);
key_size
=
min
(
req
->
max_key_size
,
rsp
.
max_key_size
);
key_size
=
min
(
req
->
max_key_size
,
rsp
.
max_key_size
);
if
(
check_enc_key_size
(
conn
,
key_size
))
if
(
check_enc_key_size
(
conn
,
key_size
))
return
SMP_ENC_KEY_SIZE
;
return
SMP_ENC_KEY_SIZE
;
/* Just works */
memset
(
smp
->
tk
,
0
,
sizeof
(
smp
->
tk
));
ret
=
smp_rand
(
smp
->
prnd
);
ret
=
smp_rand
(
smp
->
prnd
);
if
(
ret
)
if
(
ret
)
return
SMP_UNSPECIFIED
;
return
SMP_UNSPECIFIED
;
...
@@ -441,6 +599,11 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
...
@@ -441,6 +599,11 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_RSP
,
sizeof
(
rsp
),
&
rsp
);
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_RSP
,
sizeof
(
rsp
),
&
rsp
);
/* Request setup of TK */
ret
=
tk_request
(
conn
,
0
,
auth
,
rsp
.
io_capability
,
req
->
io_capability
);
if
(
ret
)
return
SMP_UNSPECIFIED
;
return
0
;
return
0
;
}
}
...
@@ -449,11 +612,14 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
...
@@ -449,11 +612,14 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
struct
smp_cmd_pairing
*
req
,
*
rsp
=
(
void
*
)
skb
->
data
;
struct
smp_cmd_pairing
*
req
,
*
rsp
=
(
void
*
)
skb
->
data
;
struct
smp_chan
*
smp
=
conn
->
smp_chan
;
struct
smp_chan
*
smp
=
conn
->
smp_chan
;
struct
hci_dev
*
hdev
=
conn
->
hcon
->
hdev
;
struct
hci_dev
*
hdev
=
conn
->
hcon
->
hdev
;
u8
key_size
;
u8
key_size
,
auth
=
SMP_AUTH_NONE
;
int
ret
;
int
ret
;
BT_DBG
(
"conn %p"
,
conn
);
BT_DBG
(
"conn %p"
,
conn
);
if
(
!
(
conn
->
hcon
->
link_mode
&
HCI_LM_MASTER
))
return
SMP_CMD_NOTSUPP
;
skb_pull
(
skb
,
sizeof
(
*
rsp
));
skb_pull
(
skb
,
sizeof
(
*
rsp
));
req
=
(
void
*
)
&
smp
->
preq
[
1
];
req
=
(
void
*
)
&
smp
->
preq
[
1
];
...
@@ -462,12 +628,6 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
...
@@ -462,12 +628,6 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
if
(
check_enc_key_size
(
conn
,
key_size
))
if
(
check_enc_key_size
(
conn
,
key_size
))
return
SMP_ENC_KEY_SIZE
;
return
SMP_ENC_KEY_SIZE
;
if
(
rsp
->
oob_flag
)
return
SMP_OOB_NOT_AVAIL
;
/* Just works */
memset
(
smp
->
tk
,
0
,
sizeof
(
smp
->
tk
));
ret
=
smp_rand
(
smp
->
prnd
);
ret
=
smp_rand
(
smp
->
prnd
);
if
(
ret
)
if
(
ret
)
return
SMP_UNSPECIFIED
;
return
SMP_UNSPECIFIED
;
...
@@ -475,6 +635,22 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
...
@@ -475,6 +635,22 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
smp
->
prsp
[
0
]
=
SMP_CMD_PAIRING_RSP
;
smp
->
prsp
[
0
]
=
SMP_CMD_PAIRING_RSP
;
memcpy
(
&
smp
->
prsp
[
1
],
rsp
,
sizeof
(
*
rsp
));
memcpy
(
&
smp
->
prsp
[
1
],
rsp
,
sizeof
(
*
rsp
));
if
((
req
->
auth_req
&
SMP_AUTH_BONDING
)
&&
(
rsp
->
auth_req
&
SMP_AUTH_BONDING
))
auth
=
SMP_AUTH_BONDING
;
auth
|=
(
req
->
auth_req
|
rsp
->
auth_req
)
&
SMP_AUTH_MITM
;
ret
=
tk_request
(
conn
,
0
,
auth
,
rsp
->
io_capability
,
req
->
io_capability
);
if
(
ret
)
return
SMP_UNSPECIFIED
;
set_bit
(
SMP_FLAG_CFM_PENDING
,
&
smp
->
smp_flags
);
/* Can't compose response until we have been confirmed */
if
(
!
test_bit
(
SMP_FLAG_TK_VALID
,
&
smp
->
smp_flags
))
return
0
;
queue_work
(
hdev
->
workqueue
,
&
smp
->
confirm
);
queue_work
(
hdev
->
workqueue
,
&
smp
->
confirm
);
return
0
;
return
0
;
...
@@ -496,8 +672,10 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
...
@@ -496,8 +672,10 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
swap128
(
smp
->
prnd
,
random
);
swap128
(
smp
->
prnd
,
random
);
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_RANDOM
,
sizeof
(
random
),
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_RANDOM
,
sizeof
(
random
),
random
);
random
);
}
else
{
}
else
if
(
test_bit
(
SMP_FLAG_TK_VALID
,
&
smp
->
smp_flags
))
{
queue_work
(
hdev
->
workqueue
,
&
smp
->
confirm
);
queue_work
(
hdev
->
workqueue
,
&
smp
->
confirm
);
}
else
{
set_bit
(
SMP_FLAG_CFM_PENDING
,
&
smp
->
smp_flags
);
}
}
return
0
;
return
0
;
...
@@ -550,7 +728,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
...
@@ -550,7 +728,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
BT_DBG
(
"conn %p"
,
conn
);
BT_DBG
(
"conn %p"
,
conn
);
hcon
->
pending_sec_level
=
BT_SECURITY_MEDIUM
;
hcon
->
pending_sec_level
=
authreq_to_seclevel
(
rp
->
auth_req
)
;
if
(
smp_ltk_encrypt
(
conn
))
if
(
smp_ltk_encrypt
(
conn
))
return
0
;
return
0
;
...
@@ -577,6 +755,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
...
@@ -577,6 +755,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
{
{
struct
hci_conn
*
hcon
=
conn
->
hcon
;
struct
hci_conn
*
hcon
=
conn
->
hcon
;
struct
smp_chan
*
smp
=
conn
->
smp_chan
;
struct
smp_chan
*
smp
=
conn
->
smp_chan
;
__u8
authreq
;
BT_DBG
(
"conn %p hcon %p level 0x%2.2x"
,
conn
,
hcon
,
sec_level
);
BT_DBG
(
"conn %p hcon %p level 0x%2.2x"
,
conn
,
hcon
,
sec_level
);
...
@@ -597,18 +776,22 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
...
@@ -597,18 +776,22 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
return
0
;
return
0
;
smp
=
smp_chan_create
(
conn
);
smp
=
smp_chan_create
(
conn
);
if
(
!
smp
)
return
1
;
authreq
=
seclevel_to_authreq
(
sec_level
);
if
(
hcon
->
link_mode
&
HCI_LM_MASTER
)
{
if
(
hcon
->
link_mode
&
HCI_LM_MASTER
)
{
struct
smp_cmd_pairing
cp
;
struct
smp_cmd_pairing
cp
;
build_pairing_cmd
(
conn
,
&
cp
,
NULL
,
SMP_AUTH_NONE
);
build_pairing_cmd
(
conn
,
&
cp
,
NULL
,
authreq
);
smp
->
preq
[
0
]
=
SMP_CMD_PAIRING_REQ
;
smp
->
preq
[
0
]
=
SMP_CMD_PAIRING_REQ
;
memcpy
(
&
smp
->
preq
[
1
],
&
cp
,
sizeof
(
cp
));
memcpy
(
&
smp
->
preq
[
1
],
&
cp
,
sizeof
(
cp
));
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_REQ
,
sizeof
(
cp
),
&
cp
);
smp_send_cmd
(
conn
,
SMP_CMD_PAIRING_REQ
,
sizeof
(
cp
),
&
cp
);
}
else
{
}
else
{
struct
smp_cmd_security_req
cp
;
struct
smp_cmd_security_req
cp
;
cp
.
auth_req
=
SMP_AUTH_NONE
;
cp
.
auth_req
=
authreq
;
smp_send_cmd
(
conn
,
SMP_CMD_SECURITY_REQ
,
sizeof
(
cp
),
&
cp
);
smp_send_cmd
(
conn
,
SMP_CMD_SECURITY_REQ
,
sizeof
(
cp
),
&
cp
);
}
}
...
@@ -637,7 +820,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
...
@@ -637,7 +820,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
skb_pull
(
skb
,
sizeof
(
*
rp
));
skb_pull
(
skb
,
sizeof
(
*
rp
));
hci_add_ltk
(
conn
->
hcon
->
hdev
,
1
,
conn
->
src
,
smp
->
smp_key_size
,
hci_add_ltk
(
conn
->
hcon
->
hdev
,
1
,
conn
->
dst
,
smp
->
smp_key_size
,
rp
->
ediv
,
rp
->
rand
,
smp
->
tk
);
rp
->
ediv
,
rp
->
rand
,
smp
->
tk
);
smp_distribute_keys
(
conn
,
1
);
smp_distribute_keys
(
conn
,
1
);
...
@@ -800,7 +983,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
...
@@ -800,7 +983,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
if
(
conn
->
hcon
->
out
||
force
)
{
if
(
conn
->
hcon
->
out
||
force
)
{
clear_bit
(
HCI_CONN_LE_SMP_PEND
,
&
conn
->
hcon
->
pend
);
clear_bit
(
HCI_CONN_LE_SMP_PEND
,
&
conn
->
hcon
->
pend
);
del_timer
(
&
conn
->
security_timer
);
cancel_delayed_work_sync
(
&
conn
->
security_timer
);
smp_chan_destroy
(
conn
);
smp_chan_destroy
(
conn
);
}
}
...
...
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