Commit dee04cac authored by John W. Linville's avatar John W. Linville
parents ce6cac88 7cbc9bd9
...@@ -246,6 +246,15 @@ enum { ...@@ -246,6 +246,15 @@ enum {
#define HCI_AT_GENERAL_BONDING 0x04 #define HCI_AT_GENERAL_BONDING 0x04
#define HCI_AT_GENERAL_BONDING_MITM 0x05 #define HCI_AT_GENERAL_BONDING_MITM 0x05
/* Link Key types */
#define HCI_LK_COMBINATION 0x00
#define HCI_LK_LOCAL_UNIT 0x01
#define HCI_LK_REMOTE_UNIT 0x02
#define HCI_LK_DEBUG_COMBINATION 0x03
#define HCI_LK_UNAUTH_COMBINATION 0x04
#define HCI_LK_AUTH_COMBINATION 0x05
#define HCI_LK_CHANGED_COMBINATION 0x06
/* ----- HCI Commands ---- */ /* ----- HCI Commands ---- */
#define HCI_OP_NOP 0x0000 #define HCI_OP_NOP 0x0000
......
...@@ -126,6 +126,8 @@ struct hci_dev { ...@@ -126,6 +126,8 @@ struct hci_dev {
__u16 sniff_min_interval; __u16 sniff_min_interval;
__u16 sniff_max_interval; __u16 sniff_max_interval;
unsigned int auto_accept_delay;
unsigned long quirks; unsigned long quirks;
atomic_t cmd_cnt; atomic_t cmd_cnt;
...@@ -226,6 +228,7 @@ struct hci_conn { ...@@ -226,6 +228,7 @@ struct hci_conn {
__u16 pkt_type; __u16 pkt_type;
__u16 link_policy; __u16 link_policy;
__u32 link_mode; __u32 link_mode;
__u8 key_type;
__u8 auth_type; __u8 auth_type;
__u8 sec_level; __u8 sec_level;
__u8 pending_sec_level; __u8 pending_sec_level;
...@@ -245,6 +248,7 @@ struct hci_conn { ...@@ -245,6 +248,7 @@ struct hci_conn {
struct timer_list disc_timer; struct timer_list disc_timer;
struct timer_list idle_timer; struct timer_list idle_timer;
struct timer_list auto_accept_timer;
struct work_struct work_add; struct work_struct work_add;
struct work_struct work_del; struct work_struct work_del;
...@@ -511,8 +515,8 @@ int hci_uuids_clear(struct hci_dev *hdev); ...@@ -511,8 +515,8 @@ int hci_uuids_clear(struct hci_dev *hdev);
int hci_link_keys_clear(struct hci_dev *hdev); int hci_link_keys_clear(struct hci_dev *hdev);
struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
u8 *key, u8 type, u8 pin_len); bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_remote_oob_data_clear(struct hci_dev *hdev); int hci_remote_oob_data_clear(struct hci_dev *hdev);
...@@ -771,15 +775,16 @@ int mgmt_index_removed(u16 index); ...@@ -771,15 +775,16 @@ int mgmt_index_removed(u16 index);
int mgmt_powered(u16 index, u8 powered); int mgmt_powered(u16 index, u8 powered);
int mgmt_discoverable(u16 index, u8 discoverable); int mgmt_discoverable(u16 index, u8 discoverable);
int mgmt_connectable(u16 index, u8 connectable); int mgmt_connectable(u16 index, u8 connectable);
int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type); int mgmt_new_key(u16 index, struct link_key *key, u8 persistent);
int mgmt_connected(u16 index, bdaddr_t *bdaddr); int mgmt_connected(u16 index, bdaddr_t *bdaddr);
int mgmt_disconnected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
int mgmt_disconnect_failed(u16 index); int mgmt_disconnect_failed(u16 index);
int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr); int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure);
int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value); int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
u8 confirm_hint);
int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
u8 status); u8 status);
...@@ -790,6 +795,7 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, ...@@ -790,6 +795,7 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
u8 *eir); u8 *eir);
int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name); int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
int mgmt_discovering(u16 index, u8 discovering);
/* HCI info for socket */ /* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk) #define hci_pi(sk) ((struct hci_pinfo *) sk)
......
...@@ -284,6 +284,25 @@ struct srej_list { ...@@ -284,6 +284,25 @@ struct srej_list {
struct l2cap_chan { struct l2cap_chan {
struct sock *sk; struct sock *sk;
struct l2cap_conn *conn;
__le16 psm;
__u16 dcid;
__u16 scid;
__u16 imtu;
__u16 omtu;
__u16 flush_to;
__u8 mode;
__le16 sport;
__u8 sec_level;
__u8 role_switch;
__u8 force_reliable;
__u8 flushable;
__u8 ident; __u8 ident;
__u8 conf_req[64]; __u8 conf_req[64];
...@@ -291,6 +310,15 @@ struct l2cap_chan { ...@@ -291,6 +310,15 @@ struct l2cap_chan {
__u8 num_conf_req; __u8 num_conf_req;
__u8 num_conf_rsp; __u8 num_conf_rsp;
__u8 fcs;
__u8 tx_win;
__u8 max_tx;
__u16 retrans_timeout;
__u16 monitor_timeout;
__u16 mps;
__u8 conf_state;
__u16 conn_state; __u16 conn_state;
__u8 next_tx_seq; __u8 next_tx_seq;
...@@ -360,32 +388,6 @@ struct l2cap_conn { ...@@ -360,32 +388,6 @@ struct l2cap_conn {
struct l2cap_pinfo { struct l2cap_pinfo {
struct bt_sock bt; struct bt_sock bt;
__le16 psm;
__u16 dcid;
__u16 scid;
__u16 imtu;
__u16 omtu;
__u16 flush_to;
__u8 mode;
__u8 fcs;
__u8 sec_level;
__u8 role_switch;
__u8 force_reliable;
__u8 flushable;
__u8 conf_state;
__u8 tx_win;
__u8 max_tx;
__u16 retrans_timeout;
__u16 monitor_timeout;
__u16 mps;
__le16 sport;
struct l2cap_conn *conn;
struct l2cap_chan *chan; struct l2cap_chan *chan;
}; };
...@@ -439,21 +441,20 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch) ...@@ -439,21 +441,20 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
#define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START) #define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START)
extern int disable_ertm; extern int disable_ertm;
extern const struct proto_ops l2cap_sock_ops;
extern struct bt_sock_list l2cap_sk_list; extern struct bt_sock_list l2cap_sk_list;
int l2cap_init_sockets(void); int l2cap_init_sockets(void);
void l2cap_cleanup_sockets(void); void l2cap_cleanup_sockets(void);
void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data);
void __l2cap_connect_rsp_defer(struct sock *sk); void __l2cap_connect_rsp_defer(struct l2cap_chan *chan);
int __l2cap_wait_ack(struct sock *sk); int __l2cap_wait_ack(struct sock *sk);
struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len); struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len); struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen); struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen);
int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
void l2cap_do_send(struct sock *sk, struct sk_buff *skb); void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb);
void l2cap_streaming_send(struct l2cap_chan *chan); void l2cap_streaming_send(struct l2cap_chan *chan);
int l2cap_ertm_send(struct l2cap_chan *chan); int l2cap_ertm_send(struct l2cap_chan *chan);
...@@ -465,7 +466,9 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent); ...@@ -465,7 +466,9 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent);
struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
int proto, gfp_t prio); int proto, gfp_t prio);
void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err);
struct l2cap_chan *l2cap_chan_alloc(struct sock *sk);
void l2cap_chan_del(struct l2cap_chan *chan, int err); void l2cap_chan_del(struct l2cap_chan *chan, int err);
int l2cap_do_connect(struct sock *sk); void l2cap_chan_free(struct l2cap_chan *chan);
int l2cap_chan_connect(struct l2cap_chan *chan);
#endif /* __L2CAP_H */ #endif /* __L2CAP_H */
...@@ -195,6 +195,10 @@ struct mgmt_cp_remove_remote_oob_data { ...@@ -195,6 +195,10 @@ struct mgmt_cp_remove_remote_oob_data {
bdaddr_t bdaddr; bdaddr_t bdaddr;
} __packed; } __packed;
#define MGMT_OP_START_DISCOVERY 0x001B
#define MGMT_OP_STOP_DISCOVERY 0x001C
#define MGMT_EV_CMD_COMPLETE 0x0001 #define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete { struct mgmt_ev_cmd_complete {
__le16 opcode; __le16 opcode;
...@@ -226,8 +230,8 @@ struct mgmt_ev_controller_error { ...@@ -226,8 +230,8 @@ struct mgmt_ev_controller_error {
#define MGMT_EV_NEW_KEY 0x000A #define MGMT_EV_NEW_KEY 0x000A
struct mgmt_ev_new_key { struct mgmt_ev_new_key {
__u8 store_hint;
struct mgmt_key_info key; struct mgmt_key_info key;
__u8 old_key_type;
} __packed; } __packed;
#define MGMT_EV_CONNECTED 0x000B #define MGMT_EV_CONNECTED 0x000B
...@@ -249,11 +253,13 @@ struct mgmt_ev_connect_failed { ...@@ -249,11 +253,13 @@ struct mgmt_ev_connect_failed {
#define MGMT_EV_PIN_CODE_REQUEST 0x000E #define MGMT_EV_PIN_CODE_REQUEST 0x000E
struct mgmt_ev_pin_code_request { struct mgmt_ev_pin_code_request {
bdaddr_t bdaddr; bdaddr_t bdaddr;
__u8 secure;
} __packed; } __packed;
#define MGMT_EV_USER_CONFIRM_REQUEST 0x000F #define MGMT_EV_USER_CONFIRM_REQUEST 0x000F
struct mgmt_ev_user_confirm_request { struct mgmt_ev_user_confirm_request {
bdaddr_t bdaddr; bdaddr_t bdaddr;
__u8 confirm_hint;
__le32 value; __le32 value;
} __packed; } __packed;
...@@ -281,3 +287,5 @@ struct mgmt_ev_remote_name { ...@@ -281,3 +287,5 @@ struct mgmt_ev_remote_name {
bdaddr_t bdaddr; bdaddr_t bdaddr;
__u8 name[MGMT_MAX_NAME_LENGTH]; __u8 name[MGMT_MAX_NAME_LENGTH];
} __packed; } __packed;
#define MGMT_EV_DISCOVERING 0x0014
...@@ -346,7 +346,8 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) ...@@ -346,7 +346,8 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst); bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst);
session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu); session->mtu = min_t(uint, l2cap_pi(sock->sk)->chan->omtu,
l2cap_pi(sock->sk)->chan->imtu);
BT_DBG("mtu %d", session->mtu); BT_DBG("mtu %d", session->mtu);
......
...@@ -269,6 +269,19 @@ static void hci_conn_idle(unsigned long arg) ...@@ -269,6 +269,19 @@ static void hci_conn_idle(unsigned long arg)
hci_conn_enter_sniff_mode(conn); hci_conn_enter_sniff_mode(conn);
} }
static void hci_conn_auto_accept(unsigned long arg)
{
struct hci_conn *conn = (void *) arg;
struct hci_dev *hdev = conn->hdev;
hci_dev_lock(hdev);
hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst),
&conn->dst);
hci_dev_unlock(hdev);
}
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
{ {
struct hci_conn *conn; struct hci_conn *conn;
...@@ -287,6 +300,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) ...@@ -287,6 +300,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
conn->auth_type = HCI_AT_GENERAL_BONDING; conn->auth_type = HCI_AT_GENERAL_BONDING;
conn->io_capability = hdev->io_capability; conn->io_capability = hdev->io_capability;
conn->remote_auth = 0xff; conn->remote_auth = 0xff;
conn->key_type = 0xff;
conn->power_save = 1; conn->power_save = 1;
conn->disc_timeout = HCI_DISCONN_TIMEOUT; conn->disc_timeout = HCI_DISCONN_TIMEOUT;
...@@ -311,6 +325,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) ...@@ -311,6 +325,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);
setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept,
(unsigned long) conn);
atomic_set(&conn->refcnt, 0); atomic_set(&conn->refcnt, 0);
...@@ -341,6 +357,8 @@ int hci_conn_del(struct hci_conn *conn) ...@@ -341,6 +357,8 @@ int hci_conn_del(struct hci_conn *conn)
del_timer(&conn->disc_timer); del_timer(&conn->disc_timer);
del_timer(&conn->auto_accept_timer);
if (conn->type == ACL_LINK) { if (conn->type == ACL_LINK) {
struct hci_conn *sco = conn->link; struct hci_conn *sco = conn->link;
if (sco) if (sco)
...@@ -535,32 +553,72 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) ...@@ -535,32 +553,72 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
return 0; return 0;
} }
/* Encrypt the the link */
static void hci_conn_encrypt(struct hci_conn *conn)
{
BT_DBG("conn %p", conn);
if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
struct hci_cp_set_conn_encrypt cp;
cp.handle = cpu_to_le16(conn->handle);
cp.encrypt = 0x01;
hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
&cp);
}
}
/* Enable security */ /* Enable security */
int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
{ {
BT_DBG("conn %p", conn); BT_DBG("conn %p", conn);
/* For sdp we don't need the link key. */
if (sec_level == BT_SECURITY_SDP) if (sec_level == BT_SECURITY_SDP)
return 1; return 1;
/* For non 2.1 devices and low security level we don't need the link
key. */
if (sec_level == BT_SECURITY_LOW && if (sec_level == BT_SECURITY_LOW &&
(!conn->ssp_mode || !conn->hdev->ssp_mode)) (!conn->ssp_mode || !conn->hdev->ssp_mode))
return 1; return 1;
if (conn->link_mode & HCI_LM_ENCRYPT) /* For other security levels we need the link key. */
return hci_conn_auth(conn, sec_level, auth_type); if (!(conn->link_mode & HCI_LM_AUTH))
goto auth;
/* An authenticated combination key has sufficient security for any
security level. */
if (conn->key_type == HCI_LK_AUTH_COMBINATION)
goto encrypt;
/* An unauthenticated combination key has sufficient security for
security level 1 and 2. */
if (conn->key_type == HCI_LK_UNAUTH_COMBINATION &&
(sec_level == BT_SECURITY_MEDIUM ||
sec_level == BT_SECURITY_LOW))
goto encrypt;
/* A combination key has always sufficient security for the security
levels 1 or 2. High security level requires the combination key
is generated using maximum PIN code length (16).
For pre 2.1 units. */
if (conn->key_type == HCI_LK_COMBINATION &&
(sec_level != BT_SECURITY_HIGH ||
conn->pin_length == 16))
goto encrypt;
auth:
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
return 0; return 0;
if (hci_conn_auth(conn, sec_level, auth_type)) { hci_conn_auth(conn, sec_level, auth_type);
struct hci_cp_set_conn_encrypt cp; return 0;
cp.handle = cpu_to_le16(conn->handle);
cp.encrypt = 1; encrypt:
hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, if (conn->link_mode & HCI_LM_ENCRYPT)
sizeof(cp), &cp); return 1;
}
hci_conn_encrypt(conn);
return 0; return 0;
} }
EXPORT_SYMBOL(hci_conn_security); EXPORT_SYMBOL(hci_conn_security);
......
...@@ -1020,18 +1020,54 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) ...@@ -1020,18 +1020,54 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
return NULL; return NULL;
} }
int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
u8 *val, u8 type, u8 pin_len) u8 key_type, u8 old_key_type)
{
/* Legacy key */
if (key_type < 0x03)
return 1;
/* Debug keys are insecure so don't store them persistently */
if (key_type == HCI_LK_DEBUG_COMBINATION)
return 0;
/* Changed combination key and there's no previous one */
if (key_type == HCI_LK_CHANGED_COMBINATION && old_key_type == 0xff)
return 0;
/* Security mode 3 case */
if (!conn)
return 1;
/* Neither local nor remote side had no-bonding as requirement */
if (conn->auth_type > 0x01 && conn->remote_auth > 0x01)
return 1;
/* Local side had dedicated bonding as requirement */
if (conn->auth_type == 0x02 || conn->auth_type == 0x03)
return 1;
/* Remote side had dedicated bonding as requirement */
if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03)
return 1;
/* If none of the above criteria match, then don't store the key
* persistently */
return 0;
}
int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
{ {
struct link_key *key, *old_key; struct link_key *key, *old_key;
u8 old_key_type; u8 old_key_type, persistent;
old_key = hci_find_link_key(hdev, bdaddr); old_key = hci_find_link_key(hdev, bdaddr);
if (old_key) { if (old_key) {
old_key_type = old_key->type; old_key_type = old_key->type;
key = old_key; key = old_key;
} else { } else {
old_key_type = 0xff; old_key_type = conn ? conn->key_type : 0xff;
key = kzalloc(sizeof(*key), GFP_ATOMIC); key = kzalloc(sizeof(*key), GFP_ATOMIC);
if (!key) if (!key)
return -ENOMEM; return -ENOMEM;
...@@ -1040,16 +1076,37 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, ...@@ -1040,16 +1076,37 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type); BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type);
/* Some buggy controller combinations generate a changed
* combination key for legacy pairing even when there's no
* previous key */
if (type == HCI_LK_CHANGED_COMBINATION &&
(!conn || conn->remote_auth == 0xff) &&
old_key_type == 0xff) {
type = HCI_LK_COMBINATION;
if (conn)
conn->key_type = type;
}
bacpy(&key->bdaddr, bdaddr); bacpy(&key->bdaddr, bdaddr);
memcpy(key->val, val, 16); memcpy(key->val, val, 16);
key->type = type;
key->pin_len = pin_len; key->pin_len = pin_len;
if (new_key) if (type == HCI_LK_CHANGED_COMBINATION)
mgmt_new_key(hdev->id, key, old_key_type);
if (type == 0x06)
key->type = old_key_type; key->type = old_key_type;
else
key->type = type;
if (!new_key)
return 0;
persistent = hci_persistent_key(hdev, conn, type, old_key_type);
mgmt_new_key(hdev->id, key, persistent);
if (!persistent) {
list_del(&key->list);
kfree(key);
}
return 0; return 0;
} }
......
...@@ -56,7 +56,9 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -56,7 +56,9 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
if (status) if (status)
return; return;
clear_bit(HCI_INQUIRY, &hdev->flags); if (test_bit(HCI_MGMT, &hdev->flags) &&
test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
mgmt_discovering(hdev->id, 0);
hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status); hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
...@@ -72,7 +74,9 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -72,7 +74,9 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
if (status) if (status)
return; return;
clear_bit(HCI_INQUIRY, &hdev->flags); if (test_bit(HCI_MGMT, &hdev->flags) &&
test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
mgmt_discovering(hdev->id, 0);
hci_conn_check_pending(hdev); hci_conn_check_pending(hdev);
} }
...@@ -841,10 +845,14 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) ...@@ -841,10 +845,14 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
if (status) { if (status) {
hci_req_complete(hdev, HCI_OP_INQUIRY, status); hci_req_complete(hdev, HCI_OP_INQUIRY, status);
hci_conn_check_pending(hdev); hci_conn_check_pending(hdev);
} else return;
set_bit(HCI_INQUIRY, &hdev->flags); }
if (test_bit(HCI_MGMT, &hdev->flags) &&
!test_and_set_bit(HCI_INQUIRY,
&hdev->flags))
mgmt_discovering(hdev->id, 1);
} }
static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
...@@ -1013,12 +1021,19 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) ...@@ -1013,12 +1021,19 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
hci_dev_lock(hdev); hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
if (conn && hci_outgoing_auth_needed(hdev, conn)) { if (!conn)
goto unlock;
if (!hci_outgoing_auth_needed(hdev, conn))
goto unlock;
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
struct hci_cp_auth_requested cp; struct hci_cp_auth_requested cp;
cp.handle = __cpu_to_le16(conn->handle); cp.handle = __cpu_to_le16(conn->handle);
hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
} }
unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
...@@ -1208,7 +1223,9 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff ...@@ -1208,7 +1223,9 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
BT_DBG("%s status %d", hdev->name, status); BT_DBG("%s status %d", hdev->name, status);
clear_bit(HCI_INQUIRY, &hdev->flags); if (test_bit(HCI_MGMT, &hdev->flags) &&
test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
mgmt_discovering(hdev->id, 0);
hci_req_complete(hdev, HCI_OP_INQUIRY, status); hci_req_complete(hdev, HCI_OP_INQUIRY, status);
...@@ -1228,6 +1245,12 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * ...@@ -1228,6 +1245,12 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_discovering(hdev->id, 1);
}
for (; num_rsp; num_rsp--, info++) { for (; num_rsp; num_rsp--, info++) {
bacpy(&data.bdaddr, &info->bdaddr); bacpy(&data.bdaddr, &info->bdaddr);
data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_rep_mode = info->pscan_rep_mode;
...@@ -1443,7 +1466,6 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s ...@@ -1443,7 +1466,6 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
conn->sec_level = conn->pending_sec_level; conn->sec_level = conn->pending_sec_level;
} else { } else {
mgmt_auth_failed(hdev->id, &conn->dst, ev->status); mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
conn->sec_level = BT_SECURITY_LOW;
} }
clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
...@@ -1501,12 +1523,19 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb ...@@ -1501,12 +1523,19 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb
mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name); mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (conn && hci_outgoing_auth_needed(hdev, conn)) { if (!conn)
goto unlock;
if (!hci_outgoing_auth_needed(hdev, conn))
goto unlock;
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
struct hci_cp_auth_requested cp; struct hci_cp_auth_requested cp;
cp.handle = __cpu_to_le16(conn->handle); cp.handle = __cpu_to_le16(conn->handle);
hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
} }
unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
...@@ -2006,9 +2035,16 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff ...@@ -2006,9 +2035,16 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
if (!test_bit(HCI_PAIRABLE, &hdev->flags)) if (!test_bit(HCI_PAIRABLE, &hdev->flags))
hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
sizeof(ev->bdaddr), &ev->bdaddr); sizeof(ev->bdaddr), &ev->bdaddr);
else if (test_bit(HCI_MGMT, &hdev->flags)) {
u8 secure;
if (test_bit(HCI_MGMT, &hdev->flags)) if (conn->pending_sec_level == BT_SECURITY_HIGH)
mgmt_pin_code_request(hdev->id, &ev->bdaddr); secure = 1;
else
secure = 0;
mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure);
}
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
...@@ -2037,17 +2073,30 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff ...@@ -2037,17 +2073,30 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
BT_DBG("%s found key type %u for %s", hdev->name, key->type, BT_DBG("%s found key type %u for %s", hdev->name, key->type,
batostr(&ev->bdaddr)); batostr(&ev->bdaddr));
if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && key->type == 0x03) { if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) &&
key->type == HCI_LK_DEBUG_COMBINATION) {
BT_DBG("%s ignoring debug key", hdev->name); BT_DBG("%s ignoring debug key", hdev->name);
goto not_found; goto not_found;
} }
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (conn) {
if (key->type == HCI_LK_UNAUTH_COMBINATION &&
conn->auth_type != 0xff &&
(conn->auth_type & 0x01)) {
BT_DBG("%s ignoring unauthenticated key", hdev->name);
goto not_found;
}
if (key->type == 0x04 && conn && conn->auth_type != 0xff && if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 &&
(conn->auth_type & 0x01)) { conn->pending_sec_level == BT_SECURITY_HIGH) {
BT_DBG("%s ignoring unauthenticated key", hdev->name); BT_DBG("%s ignoring key unauthenticated for high \
goto not_found; security", hdev->name);
goto not_found;
}
conn->key_type = key->type;
conn->pin_length = key->pin_len;
} }
bacpy(&cp.bdaddr, &ev->bdaddr); bacpy(&cp.bdaddr, &ev->bdaddr);
...@@ -2079,11 +2128,15 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff ...@@ -2079,11 +2128,15 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
hci_conn_hold(conn); hci_conn_hold(conn);
conn->disc_timeout = HCI_DISCONN_TIMEOUT; conn->disc_timeout = HCI_DISCONN_TIMEOUT;
pin_len = conn->pin_length; pin_len = conn->pin_length;
if (ev->key_type != HCI_LK_CHANGED_COMBINATION)
conn->key_type = ev->key_type;
hci_conn_put(conn); hci_conn_put(conn);
} }
if (test_bit(HCI_LINK_KEYS, &hdev->flags)) if (test_bit(HCI_LINK_KEYS, &hdev->flags))
hci_add_link_key(hdev, 1, &ev->bdaddr, ev->link_key, hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key,
ev->key_type, pin_len); ev->key_type, pin_len);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -2158,6 +2211,12 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct ...@@ -2158,6 +2211,12 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_discovering(hdev->id, 1);
}
if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) { if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
struct inquiry_info_with_rssi_and_pscan_mode *info; struct inquiry_info_with_rssi_and_pscan_mode *info;
info = (void *) (skb->data + 1); info = (void *) (skb->data + 1);
...@@ -2320,6 +2379,12 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct ...@@ -2320,6 +2379,12 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
if (!num_rsp) if (!num_rsp)
return; return;
if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_discovering(hdev->id, 1);
}
hci_dev_lock(hdev); hci_dev_lock(hdev);
for (; num_rsp; num_rsp--, info++) { for (; num_rsp; num_rsp--, info++) {
...@@ -2353,7 +2418,7 @@ static inline u8 hci_get_auth_req(struct hci_conn *conn) ...@@ -2353,7 +2418,7 @@ static inline u8 hci_get_auth_req(struct hci_conn *conn)
/* If remote requests no-bonding follow that lead */ /* If remote requests no-bonding follow that lead */
if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01) if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01)
return 0x00; return conn->remote_auth | (conn->auth_type & 0x01);
return conn->auth_type; return conn->auth_type;
} }
...@@ -2382,7 +2447,8 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff ...@@ -2382,7 +2447,8 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
bacpy(&cp.bdaddr, &ev->bdaddr); bacpy(&cp.bdaddr, &ev->bdaddr);
cp.capability = conn->io_capability; cp.capability = conn->io_capability;
cp.authentication = hci_get_auth_req(conn); conn->auth_type = hci_get_auth_req(conn);
cp.authentication = conn->auth_type;
if ((conn->out == 0x01 || conn->remote_oob == 0x01) && if ((conn->out == 0x01 || conn->remote_oob == 0x01) &&
hci_find_remote_oob_data(hdev, &conn->dst)) hci_find_remote_oob_data(hdev, &conn->dst))
...@@ -2396,7 +2462,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff ...@@ -2396,7 +2462,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
struct hci_cp_io_capability_neg_reply cp; struct hci_cp_io_capability_neg_reply cp;
bacpy(&cp.bdaddr, &ev->bdaddr); bacpy(&cp.bdaddr, &ev->bdaddr);
cp.reason = 0x16; /* Pairing not allowed */ cp.reason = 0x18; /* Pairing not allowed */
hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY, hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY,
sizeof(cp), &cp); sizeof(cp), &cp);
...@@ -2431,14 +2497,67 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, ...@@ -2431,14 +2497,67 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct hci_ev_user_confirm_req *ev = (void *) skb->data; struct hci_ev_user_confirm_req *ev = (void *) skb->data;
int loc_mitm, rem_mitm, confirm_hint = 0;
struct hci_conn *conn;
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags)) if (!test_bit(HCI_MGMT, &hdev->flags))
mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey); goto unlock;
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (!conn)
goto unlock;
loc_mitm = (conn->auth_type & 0x01);
rem_mitm = (conn->remote_auth & 0x01);
/* If we require MITM but the remote device can't provide that
* (it has NoInputNoOutput) then reject the confirmation
* request. The only exception is when we're dedicated bonding
* initiators (connect_cfm_cb set) since then we always have the MITM
* bit set. */
if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) {
BT_DBG("Rejecting request: remote device can't provide MITM");
hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY,
sizeof(ev->bdaddr), &ev->bdaddr);
goto unlock;
}
/* If no side requires MITM protection; auto-accept */
if ((!loc_mitm || conn->remote_cap == 0x03) &&
(!rem_mitm || conn->io_capability == 0x03)) {
/* If we're not the initiators request authorization to
* proceed from user space (mgmt_user_confirm with
* confirm_hint set to 1). */
if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
BT_DBG("Confirming auto-accept as acceptor");
confirm_hint = 1;
goto confirm;
}
BT_DBG("Auto-accept of user confirmation with %ums delay",
hdev->auto_accept_delay);
if (hdev->auto_accept_delay > 0) {
int delay = msecs_to_jiffies(hdev->auto_accept_delay);
mod_timer(&conn->auto_accept_timer, jiffies + delay);
goto unlock;
}
hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY,
sizeof(ev->bdaddr), &ev->bdaddr);
goto unlock;
}
confirm:
mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey,
confirm_hint);
unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
......
...@@ -511,6 +511,35 @@ static const struct file_operations uuids_fops = { ...@@ -511,6 +511,35 @@ static const struct file_operations uuids_fops = {
.release = single_release, .release = single_release,
}; };
static int auto_accept_delay_set(void *data, u64 val)
{
struct hci_dev *hdev = data;
hci_dev_lock_bh(hdev);
hdev->auto_accept_delay = val;
hci_dev_unlock_bh(hdev);
return 0;
}
static int auto_accept_delay_get(void *data, u64 *val)
{
struct hci_dev *hdev = data;
hci_dev_lock_bh(hdev);
*val = hdev->auto_accept_delay;
hci_dev_unlock_bh(hdev);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get,
auto_accept_delay_set, "%llu\n");
int hci_register_sysfs(struct hci_dev *hdev) int hci_register_sysfs(struct hci_dev *hdev)
{ {
struct device *dev = &hdev->dev; struct device *dev = &hdev->dev;
...@@ -545,6 +574,8 @@ int hci_register_sysfs(struct hci_dev *hdev) ...@@ -545,6 +574,8 @@ int hci_register_sysfs(struct hci_dev *hdev)
debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops); debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops);
debugfs_create_file("auto_accept_delay", 0444, hdev->debugfs, hdev,
&auto_accept_delay_fops);
return 0; return 0;
} }
......
...@@ -979,8 +979,10 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, ...@@ -979,8 +979,10 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst); bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu); session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu,
session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu); l2cap_pi(ctrl_sock->sk)->chan->imtu);
session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->chan->omtu,
l2cap_pi(intr_sock->sk)->chan->imtu);
BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu); BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
......
This diff is collapsed.
This diff is collapsed.
...@@ -945,7 +945,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) ...@@ -945,7 +945,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
for (i = 0; i < key_count; i++) { for (i = 0; i < key_count; i++) {
struct mgmt_key_info *key = &cp->keys[i]; struct mgmt_key_info *key = &cp->keys[i];
hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type, hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
key->pin_len); key->pin_len);
} }
...@@ -1569,6 +1569,75 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, ...@@ -1569,6 +1569,75 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
return err; return err;
} }
static int start_discovery(struct sock *sk, u16 index)
{
u8 lap[3] = { 0x33, 0x8b, 0x9e };
struct hci_cp_inquiry cp;
struct pending_cmd *cmd;
struct hci_dev *hdev;
int err;
BT_DBG("hci%u", index);
hdev = hci_dev_get(index);
if (!hdev)
return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
if (!cmd) {
err = -ENOMEM;
goto failed;
}
memset(&cp, 0, sizeof(cp));
memcpy(&cp.lap, lap, 3);
cp.length = 0x08;
cp.num_rsp = 0x00;
err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
if (err < 0)
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
}
static int stop_discovery(struct sock *sk, u16 index)
{
struct hci_dev *hdev;
struct pending_cmd *cmd;
int err;
BT_DBG("hci%u", index);
hdev = hci_dev_get(index);
if (!hdev)
return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
if (!cmd) {
err = -ENOMEM;
goto failed;
}
err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
if (err < 0)
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
}
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
{ {
unsigned char *buf; unsigned char *buf;
...@@ -1677,7 +1746,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) ...@@ -1677,7 +1746,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr), err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
len); len);
break; break;
case MGMT_OP_START_DISCOVERY:
err = start_discovery(sk, index);
break;
case MGMT_OP_STOP_DISCOVERY:
err = stop_discovery(sk, index);
break;
default: default:
BT_DBG("Unknown op %u", opcode); BT_DBG("Unknown op %u", opcode);
err = cmd_status(sk, index, opcode, 0x01); err = cmd_status(sk, index, opcode, 0x01);
...@@ -1784,17 +1858,17 @@ int mgmt_connectable(u16 index, u8 connectable) ...@@ -1784,17 +1858,17 @@ int mgmt_connectable(u16 index, u8 connectable)
return ret; return ret;
} }
int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type) int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
{ {
struct mgmt_ev_new_key ev; struct mgmt_ev_new_key ev;
memset(&ev, 0, sizeof(ev)); memset(&ev, 0, sizeof(ev));
ev.store_hint = persistent;
bacpy(&ev.key.bdaddr, &key->bdaddr); bacpy(&ev.key.bdaddr, &key->bdaddr);
ev.key.type = key->type; ev.key.type = key->type;
memcpy(ev.key.val, key->val, 16); memcpy(ev.key.val, key->val, 16);
ev.key.pin_len = key->pin_len; ev.key.pin_len = key->pin_len;
ev.old_key_type = old_key_type;
return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL); return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
} }
...@@ -1868,11 +1942,12 @@ int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status) ...@@ -1868,11 +1942,12 @@ int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL); return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
} }
int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr) int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
{ {
struct mgmt_ev_pin_code_request ev; struct mgmt_ev_pin_code_request ev;
bacpy(&ev.bdaddr, bdaddr); bacpy(&ev.bdaddr, bdaddr);
ev.secure = secure;
return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev), return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
NULL); NULL);
...@@ -1920,13 +1995,15 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status) ...@@ -1920,13 +1995,15 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
return err; return err;
} }
int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value) int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
u8 confirm_hint)
{ {
struct mgmt_ev_user_confirm_request ev; struct mgmt_ev_user_confirm_request ev;
BT_DBG("hci%u", index); BT_DBG("hci%u", index);
bacpy(&ev.bdaddr, bdaddr); bacpy(&ev.bdaddr, bdaddr);
ev.confirm_hint = confirm_hint;
put_unaligned_le32(value, &ev.value); put_unaligned_le32(value, &ev.value);
return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev), return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
...@@ -2075,3 +2152,9 @@ int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name) ...@@ -2075,3 +2152,9 @@ int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL); return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
} }
int mgmt_discovering(u16 index, u8 discovering)
{
return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
sizeof(discovering), NULL);
}
...@@ -232,6 +232,8 @@ static int rfcomm_l2sock_create(struct socket **sock) ...@@ -232,6 +232,8 @@ static int rfcomm_l2sock_create(struct socket **sock)
static inline int rfcomm_check_security(struct rfcomm_dlc *d) static inline int rfcomm_check_security(struct rfcomm_dlc *d)
{ {
struct sock *sk = d->session->sock->sk; struct sock *sk = d->session->sock->sk;
struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
__u8 auth_type; __u8 auth_type;
switch (d->sec_level) { switch (d->sec_level) {
...@@ -246,8 +248,7 @@ static inline int rfcomm_check_security(struct rfcomm_dlc *d) ...@@ -246,8 +248,7 @@ static inline int rfcomm_check_security(struct rfcomm_dlc *d)
break; break;
} }
return hci_conn_security(l2cap_pi(sk)->conn->hcon, d->sec_level, return hci_conn_security(conn->hcon, d->sec_level, auth_type);
auth_type);
} }
static void rfcomm_session_timeout(unsigned long arg) static void rfcomm_session_timeout(unsigned long arg)
...@@ -710,10 +711,10 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, ...@@ -710,10 +711,10 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
/* Set L2CAP options */ /* Set L2CAP options */
sk = sock->sk; sk = sock->sk;
lock_sock(sk); lock_sock(sk);
l2cap_pi(sk)->imtu = l2cap_mtu; l2cap_pi(sk)->chan->imtu = l2cap_mtu;
l2cap_pi(sk)->sec_level = sec_level; l2cap_pi(sk)->chan->sec_level = sec_level;
if (l2cap_ertm) if (l2cap_ertm)
l2cap_pi(sk)->mode = L2CAP_MODE_ERTM; l2cap_pi(sk)->chan->mode = L2CAP_MODE_ERTM;
release_sock(sk); release_sock(sk);
s = rfcomm_session_add(sock, BT_BOUND); s = rfcomm_session_add(sock, BT_BOUND);
...@@ -1241,6 +1242,7 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci) ...@@ -1241,6 +1242,7 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
void rfcomm_dlc_accept(struct rfcomm_dlc *d) void rfcomm_dlc_accept(struct rfcomm_dlc *d)
{ {
struct sock *sk = d->session->sock->sk; struct sock *sk = d->session->sock->sk;
struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
BT_DBG("dlc %p", d); BT_DBG("dlc %p", d);
...@@ -1254,7 +1256,7 @@ void rfcomm_dlc_accept(struct rfcomm_dlc *d) ...@@ -1254,7 +1256,7 @@ void rfcomm_dlc_accept(struct rfcomm_dlc *d)
rfcomm_dlc_unlock(d); rfcomm_dlc_unlock(d);
if (d->role_switch) if (d->role_switch)
hci_conn_switch_role(l2cap_pi(sk)->conn->hcon, 0x00); hci_conn_switch_role(conn->hcon, 0x00);
rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig); rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
} }
...@@ -1890,7 +1892,8 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s) ...@@ -1890,7 +1892,8 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s)
/* We should adjust MTU on incoming sessions. /* We should adjust MTU on incoming sessions.
* L2CAP MTU minus UIH header and FCS. */ * L2CAP MTU minus UIH header and FCS. */
s->mtu = min(l2cap_pi(nsock->sk)->omtu, l2cap_pi(nsock->sk)->imtu) - 5; s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu,
l2cap_pi(nsock->sk)->chan->imtu) - 5;
rfcomm_schedule(); rfcomm_schedule();
} else } else
...@@ -1909,7 +1912,7 @@ static inline void rfcomm_check_connection(struct rfcomm_session *s) ...@@ -1909,7 +1912,7 @@ static inline void rfcomm_check_connection(struct rfcomm_session *s)
/* We can adjust MTU on outgoing sessions. /* We can adjust MTU on outgoing sessions.
* L2CAP MTU minus UIH header and FCS. */ * L2CAP MTU minus UIH header and FCS. */
s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5; s->mtu = min(l2cap_pi(sk)->chan->omtu, l2cap_pi(sk)->chan->imtu) - 5;
rfcomm_send_sabm(s, 0); rfcomm_send_sabm(s, 0);
break; break;
...@@ -1992,7 +1995,7 @@ static int rfcomm_add_listener(bdaddr_t *ba) ...@@ -1992,7 +1995,7 @@ static int rfcomm_add_listener(bdaddr_t *ba)
/* Set L2CAP options */ /* Set L2CAP options */
sk = sock->sk; sk = sock->sk;
lock_sock(sk); lock_sock(sk);
l2cap_pi(sk)->imtu = l2cap_mtu; l2cap_pi(sk)->chan->imtu = l2cap_mtu;
release_sock(sk); release_sock(sk);
/* Start listening on the socket */ /* Start listening on the socket */
......
...@@ -743,6 +743,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u ...@@ -743,6 +743,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct sock *l2cap_sk; struct sock *l2cap_sk;
struct rfcomm_conninfo cinfo; struct rfcomm_conninfo cinfo;
struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
int len, err = 0; int len, err = 0;
u32 opt; u32 opt;
...@@ -787,8 +788,8 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u ...@@ -787,8 +788,8 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk; l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk;
cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle; cinfo.hci_handle = conn->hcon->handle;
memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3); memcpy(cinfo.dev_class, conn->hcon->dev_class, 3);
len = min_t(unsigned int, len, sizeof(cinfo)); len = min_t(unsigned int, len, sizeof(cinfo));
if (copy_to_user(optval, (char *) &cinfo, len)) if (copy_to_user(optval, (char *) &cinfo, len))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment