mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-16 09:13:55 +08:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next-2.6
This commit is contained in:
commit
dee04cac28
@ -246,6 +246,15 @@ enum {
|
||||
#define HCI_AT_GENERAL_BONDING 0x04
|
||||
#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 ---- */
|
||||
#define HCI_OP_NOP 0x0000
|
||||
|
||||
|
@ -126,6 +126,8 @@ struct hci_dev {
|
||||
__u16 sniff_min_interval;
|
||||
__u16 sniff_max_interval;
|
||||
|
||||
unsigned int auto_accept_delay;
|
||||
|
||||
unsigned long quirks;
|
||||
|
||||
atomic_t cmd_cnt;
|
||||
@ -226,6 +228,7 @@ struct hci_conn {
|
||||
__u16 pkt_type;
|
||||
__u16 link_policy;
|
||||
__u32 link_mode;
|
||||
__u8 key_type;
|
||||
__u8 auth_type;
|
||||
__u8 sec_level;
|
||||
__u8 pending_sec_level;
|
||||
@ -245,6 +248,7 @@ struct hci_conn {
|
||||
|
||||
struct timer_list disc_timer;
|
||||
struct timer_list idle_timer;
|
||||
struct timer_list auto_accept_timer;
|
||||
|
||||
struct work_struct work_add;
|
||||
struct work_struct work_del;
|
||||
@ -511,8 +515,8 @@ int hci_uuids_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);
|
||||
int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
|
||||
u8 *key, u8 type, u8 pin_len);
|
||||
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);
|
||||
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
|
||||
int hci_remote_oob_data_clear(struct hci_dev *hdev);
|
||||
@ -771,15 +775,16 @@ int mgmt_index_removed(u16 index);
|
||||
int mgmt_powered(u16 index, u8 powered);
|
||||
int mgmt_discoverable(u16 index, u8 discoverable);
|
||||
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_disconnected(u16 index, bdaddr_t *bdaddr);
|
||||
int mgmt_disconnect_failed(u16 index);
|
||||
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_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_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
|
||||
u8 status);
|
||||
@ -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,
|
||||
u8 *eir);
|
||||
int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
|
||||
int mgmt_discovering(u16 index, u8 discovering);
|
||||
|
||||
/* HCI info for socket */
|
||||
#define hci_pi(sk) ((struct hci_pinfo *) sk)
|
||||
|
@ -284,6 +284,25 @@ struct srej_list {
|
||||
|
||||
struct l2cap_chan {
|
||||
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 conf_req[64];
|
||||
@ -291,6 +310,15 @@ struct l2cap_chan {
|
||||
__u8 num_conf_req;
|
||||
__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;
|
||||
|
||||
__u8 next_tx_seq;
|
||||
@ -360,32 +388,6 @@ struct l2cap_conn {
|
||||
|
||||
struct l2cap_pinfo {
|
||||
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;
|
||||
};
|
||||
|
||||
@ -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)
|
||||
|
||||
extern int disable_ertm;
|
||||
extern const struct proto_ops l2cap_sock_ops;
|
||||
extern struct bt_sock_list l2cap_sk_list;
|
||||
|
||||
int l2cap_init_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_connect_rsp_defer(struct sock *sk);
|
||||
void __l2cap_connect_rsp_defer(struct l2cap_chan *chan);
|
||||
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_basic_pdu(struct sock *sk, 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_connless_pdu(struct l2cap_chan *chan, 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 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);
|
||||
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);
|
||||
int l2cap_ertm_send(struct l2cap_chan *chan);
|
||||
|
||||
@ -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,
|
||||
int proto, gfp_t prio);
|
||||
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);
|
||||
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 */
|
||||
|
@ -195,6 +195,10 @@ struct mgmt_cp_remove_remote_oob_data {
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_START_DISCOVERY 0x001B
|
||||
|
||||
#define MGMT_OP_STOP_DISCOVERY 0x001C
|
||||
|
||||
#define MGMT_EV_CMD_COMPLETE 0x0001
|
||||
struct mgmt_ev_cmd_complete {
|
||||
__le16 opcode;
|
||||
@ -226,8 +230,8 @@ struct mgmt_ev_controller_error {
|
||||
|
||||
#define MGMT_EV_NEW_KEY 0x000A
|
||||
struct mgmt_ev_new_key {
|
||||
__u8 store_hint;
|
||||
struct mgmt_key_info key;
|
||||
__u8 old_key_type;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CONNECTED 0x000B
|
||||
@ -249,11 +253,13 @@ struct mgmt_ev_connect_failed {
|
||||
#define MGMT_EV_PIN_CODE_REQUEST 0x000E
|
||||
struct mgmt_ev_pin_code_request {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 secure;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_USER_CONFIRM_REQUEST 0x000F
|
||||
struct mgmt_ev_user_confirm_request {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 confirm_hint;
|
||||
__le32 value;
|
||||
} __packed;
|
||||
|
||||
@ -281,3 +287,5 @@ struct mgmt_ev_remote_name {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 name[MGMT_MAX_NAME_LENGTH];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DISCOVERING 0x0014
|
||||
|
@ -346,7 +346,8 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
|
||||
|
||||
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);
|
||||
|
||||
|
@ -269,6 +269,19 @@ static void hci_conn_idle(unsigned long arg)
|
||||
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 *conn;
|
||||
@ -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->io_capability = hdev->io_capability;
|
||||
conn->remote_auth = 0xff;
|
||||
conn->key_type = 0xff;
|
||||
|
||||
conn->power_save = 1;
|
||||
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)
|
||||
|
||||
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->auto_accept_timer, hci_conn_auto_accept,
|
||||
(unsigned long) conn);
|
||||
|
||||
atomic_set(&conn->refcnt, 0);
|
||||
|
||||
@ -341,6 +357,8 @@ int hci_conn_del(struct hci_conn *conn)
|
||||
|
||||
del_timer(&conn->disc_timer);
|
||||
|
||||
del_timer(&conn->auto_accept_timer);
|
||||
|
||||
if (conn->type == ACL_LINK) {
|
||||
struct hci_conn *sco = conn->link;
|
||||
if (sco)
|
||||
@ -535,32 +553,72 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
||||
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 */
|
||||
int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
||||
{
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
/* For sdp we don't need the link key. */
|
||||
if (sec_level == BT_SECURITY_SDP)
|
||||
return 1;
|
||||
|
||||
/* For non 2.1 devices and low security level we don't need the link
|
||||
key. */
|
||||
if (sec_level == BT_SECURITY_LOW &&
|
||||
(!conn->ssp_mode || !conn->hdev->ssp_mode))
|
||||
return 1;
|
||||
|
||||
if (conn->link_mode & HCI_LM_ENCRYPT)
|
||||
return hci_conn_auth(conn, sec_level, auth_type);
|
||||
/* For other security levels we need the link key. */
|
||||
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))
|
||||
return 0;
|
||||
|
||||
if (hci_conn_auth(conn, sec_level, auth_type)) {
|
||||
struct hci_cp_set_conn_encrypt cp;
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
cp.encrypt = 1;
|
||||
hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
|
||||
sizeof(cp), &cp);
|
||||
}
|
||||
hci_conn_auth(conn, sec_level, auth_type);
|
||||
return 0;
|
||||
|
||||
encrypt:
|
||||
if (conn->link_mode & HCI_LM_ENCRYPT)
|
||||
return 1;
|
||||
|
||||
hci_conn_encrypt(conn);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hci_conn_security);
|
||||
|
@ -1020,18 +1020,54 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
|
||||
u8 *val, u8 type, u8 pin_len)
|
||||
static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
|
||||
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;
|
||||
u8 old_key_type;
|
||||
u8 old_key_type, persistent;
|
||||
|
||||
old_key = hci_find_link_key(hdev, bdaddr);
|
||||
if (old_key) {
|
||||
old_key_type = old_key->type;
|
||||
key = old_key;
|
||||
} else {
|
||||
old_key_type = 0xff;
|
||||
old_key_type = conn ? conn->key_type : 0xff;
|
||||
key = kzalloc(sizeof(*key), GFP_ATOMIC);
|
||||
if (!key)
|
||||
return -ENOMEM;
|
||||
@ -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);
|
||||
|
||||
/* 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);
|
||||
memcpy(key->val, val, 16);
|
||||
key->type = type;
|
||||
key->pin_len = pin_len;
|
||||
|
||||
if (new_key)
|
||||
mgmt_new_key(hdev->id, key, old_key_type);
|
||||
|
||||
if (type == 0x06)
|
||||
if (type == HCI_LK_CHANGED_COMBINATION)
|
||||
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;
|
||||
}
|
||||
|
@ -56,7 +56,9 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
if (status)
|
||||
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);
|
||||
|
||||
@ -72,7 +74,9 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
if (status)
|
||||
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);
|
||||
}
|
||||
@ -841,10 +845,14 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
|
||||
|
||||
if (status) {
|
||||
hci_req_complete(hdev, HCI_OP_INQUIRY, status);
|
||||
|
||||
hci_conn_check_pending(hdev);
|
||||
} else
|
||||
set_bit(HCI_INQUIRY, &hdev->flags);
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
@ -1013,12 +1021,19 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
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;
|
||||
cp.handle = __cpu_to_le16(conn->handle);
|
||||
hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
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);
|
||||
|
||||
@ -1228,6 +1245,12 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
|
||||
|
||||
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++) {
|
||||
bacpy(&data.bdaddr, &info->bdaddr);
|
||||
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
|
||||
conn->sec_level = conn->pending_sec_level;
|
||||
} else {
|
||||
mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
|
||||
conn->sec_level = BT_SECURITY_LOW;
|
||||
}
|
||||
|
||||
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
|
||||
mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name);
|
||||
|
||||
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;
|
||||
cp.handle = __cpu_to_le16(conn->handle);
|
||||
hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
@ -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))
|
||||
hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
|
||||
sizeof(ev->bdaddr), &ev->bdaddr);
|
||||
else if (test_bit(HCI_MGMT, &hdev->flags)) {
|
||||
u8 secure;
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_pin_code_request(hdev->id, &ev->bdaddr);
|
||||
if (conn->pending_sec_level == BT_SECURITY_HIGH)
|
||||
secure = 1;
|
||||
else
|
||||
secure = 0;
|
||||
|
||||
mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
@ -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,
|
||||
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);
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
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 &&
|
||||
(conn->auth_type & 0x01)) {
|
||||
BT_DBG("%s ignoring unauthenticated key", hdev->name);
|
||||
goto not_found;
|
||||
if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 &&
|
||||
conn->pending_sec_level == BT_SECURITY_HIGH) {
|
||||
BT_DBG("%s ignoring key unauthenticated for high \
|
||||
security", hdev->name);
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
conn->key_type = key->type;
|
||||
conn->pin_length = key->pin_len;
|
||||
}
|
||||
|
||||
bacpy(&cp.bdaddr, &ev->bdaddr);
|
||||
@ -2079,11 +2128,15 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
|
||||
hci_conn_hold(conn);
|
||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
pin_len = conn->pin_length;
|
||||
|
||||
if (ev->key_type != HCI_LK_CHANGED_COMBINATION)
|
||||
conn->key_type = ev->key_type;
|
||||
|
||||
hci_conn_put(conn);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
@ -2158,6 +2211,12 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
|
||||
|
||||
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)) {
|
||||
struct inquiry_info_with_rssi_and_pscan_mode *info;
|
||||
info = (void *) (skb->data + 1);
|
||||
@ -2320,6 +2379,12 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
|
||||
if (!num_rsp)
|
||||
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);
|
||||
|
||||
for (; num_rsp; num_rsp--, info++) {
|
||||
@ -2353,7 +2418,7 @@ static inline u8 hci_get_auth_req(struct hci_conn *conn)
|
||||
|
||||
/* If remote requests no-bonding follow that lead */
|
||||
if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01)
|
||||
return 0x00;
|
||||
return conn->remote_auth | (conn->auth_type & 0x01);
|
||||
|
||||
return conn->auth_type;
|
||||
}
|
||||
@ -2382,7 +2447,8 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
|
||||
|
||||
bacpy(&cp.bdaddr, &ev->bdaddr);
|
||||
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) &&
|
||||
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
|
||||
struct hci_cp_io_capability_neg_reply cp;
|
||||
|
||||
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,
|
||||
sizeof(cp), &cp);
|
||||
@ -2431,14 +2497,67 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
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);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey);
|
||||
if (!test_bit(HCI_MGMT, &hdev->flags))
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -511,6 +511,35 @@ static const struct file_operations uuids_fops = {
|
||||
.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)
|
||||
{
|
||||
struct device *dev = &hdev->dev;
|
||||
@ -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("auto_accept_delay", 0444, hdev->debugfs, hdev,
|
||||
&auto_accept_delay_fops);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu);
|
||||
session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu);
|
||||
session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu,
|
||||
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);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,6 +30,8 @@
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <net/bluetooth/l2cap.h>
|
||||
|
||||
static const struct proto_ops l2cap_sock_ops;
|
||||
|
||||
/* ---- L2CAP timers ---- */
|
||||
static void l2cap_sock_timeout(unsigned long arg)
|
||||
{
|
||||
@ -51,7 +53,7 @@ static void l2cap_sock_timeout(unsigned long arg)
|
||||
if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
|
||||
reason = ECONNREFUSED;
|
||||
else if (sk->sk_state == BT_CONNECT &&
|
||||
l2cap_pi(sk)->sec_level != BT_SECURITY_SDP)
|
||||
l2cap_pi(sk)->chan->sec_level != BT_SECURITY_SDP)
|
||||
reason = ECONNREFUSED;
|
||||
else
|
||||
reason = ETIMEDOUT;
|
||||
@ -80,9 +82,13 @@ static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
|
||||
{
|
||||
struct sock *sk;
|
||||
struct hlist_node *node;
|
||||
sk_for_each(sk, node, &l2cap_sk_list.head)
|
||||
if (l2cap_pi(sk)->sport == psm && !bacmp(&bt_sk(sk)->src, src))
|
||||
sk_for_each(sk, node, &l2cap_sk_list.head) {
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
|
||||
if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src))
|
||||
goto found;
|
||||
}
|
||||
|
||||
sk = NULL;
|
||||
found:
|
||||
return sk;
|
||||
@ -91,6 +97,7 @@ found:
|
||||
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
struct sockaddr_l2 la;
|
||||
int len, err = 0;
|
||||
|
||||
@ -136,17 +143,17 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
|
||||
} else {
|
||||
/* Save source address */
|
||||
bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
|
||||
l2cap_pi(sk)->psm = la.l2_psm;
|
||||
l2cap_pi(sk)->sport = la.l2_psm;
|
||||
chan->psm = la.l2_psm;
|
||||
chan->sport = la.l2_psm;
|
||||
sk->sk_state = BT_BOUND;
|
||||
|
||||
if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
|
||||
__le16_to_cpu(la.l2_psm) == 0x0003)
|
||||
l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
|
||||
chan->sec_level = BT_SECURITY_SDP;
|
||||
}
|
||||
|
||||
if (la.l2_cid)
|
||||
l2cap_pi(sk)->scid = la.l2_cid;
|
||||
chan->scid = la.l2_cid;
|
||||
|
||||
write_unlock_bh(&l2cap_sk_list.lock);
|
||||
|
||||
@ -158,6 +165,7 @@ done:
|
||||
static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
struct sockaddr_l2 la;
|
||||
int len, err = 0;
|
||||
|
||||
@ -182,7 +190,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (l2cap_pi(sk)->mode) {
|
||||
switch (chan->mode) {
|
||||
case L2CAP_MODE_BASIC:
|
||||
break;
|
||||
case L2CAP_MODE_ERTM:
|
||||
@ -226,10 +234,10 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
|
||||
|
||||
/* Set destination address and psm */
|
||||
bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
|
||||
l2cap_pi(sk)->psm = la.l2_psm;
|
||||
l2cap_pi(sk)->dcid = la.l2_cid;
|
||||
chan->psm = la.l2_psm;
|
||||
chan->dcid = la.l2_cid;
|
||||
|
||||
err = l2cap_do_connect(sk);
|
||||
err = l2cap_chan_connect(l2cap_pi(sk)->chan);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
@ -244,6 +252,7 @@ done:
|
||||
static int l2cap_sock_listen(struct socket *sock, int backlog)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
int err = 0;
|
||||
|
||||
BT_DBG("sk %p backlog %d", sk, backlog);
|
||||
@ -256,7 +265,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (l2cap_pi(sk)->mode) {
|
||||
switch (chan->mode) {
|
||||
case L2CAP_MODE_BASIC:
|
||||
break;
|
||||
case L2CAP_MODE_ERTM:
|
||||
@ -269,7 +278,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->scid) {
|
||||
if (!chan->psm && !chan->scid) {
|
||||
bdaddr_t *src = &bt_sk(sk)->src;
|
||||
u16 psm;
|
||||
|
||||
@ -279,8 +288,8 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
|
||||
|
||||
for (psm = 0x1001; psm < 0x1100; psm += 2)
|
||||
if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) {
|
||||
l2cap_pi(sk)->psm = cpu_to_le16(psm);
|
||||
l2cap_pi(sk)->sport = cpu_to_le16(psm);
|
||||
chan->psm = cpu_to_le16(psm);
|
||||
chan->sport = cpu_to_le16(psm);
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
@ -360,6 +369,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
|
||||
{
|
||||
struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
|
||||
struct sock *sk = sock->sk;
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
|
||||
BT_DBG("sock %p, sk %p", sock, sk);
|
||||
|
||||
@ -367,13 +377,13 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
|
||||
*len = sizeof(struct sockaddr_l2);
|
||||
|
||||
if (peer) {
|
||||
la->l2_psm = l2cap_pi(sk)->psm;
|
||||
la->l2_psm = chan->psm;
|
||||
bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst);
|
||||
la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid);
|
||||
la->l2_cid = cpu_to_le16(chan->dcid);
|
||||
} else {
|
||||
la->l2_psm = l2cap_pi(sk)->sport;
|
||||
la->l2_psm = chan->sport;
|
||||
bacpy(&la->l2_bdaddr, &bt_sk(sk)->src);
|
||||
la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid);
|
||||
la->l2_cid = cpu_to_le16(chan->scid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -382,6 +392,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
|
||||
static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
struct l2cap_options opts;
|
||||
struct l2cap_conninfo cinfo;
|
||||
int len, err = 0;
|
||||
@ -397,13 +408,13 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
|
||||
switch (optname) {
|
||||
case L2CAP_OPTIONS:
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.imtu = l2cap_pi(sk)->imtu;
|
||||
opts.omtu = l2cap_pi(sk)->omtu;
|
||||
opts.flush_to = l2cap_pi(sk)->flush_to;
|
||||
opts.mode = l2cap_pi(sk)->mode;
|
||||
opts.fcs = l2cap_pi(sk)->fcs;
|
||||
opts.max_tx = l2cap_pi(sk)->max_tx;
|
||||
opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win;
|
||||
opts.imtu = chan->imtu;
|
||||
opts.omtu = chan->omtu;
|
||||
opts.flush_to = chan->flush_to;
|
||||
opts.mode = chan->mode;
|
||||
opts.fcs = chan->fcs;
|
||||
opts.max_tx = chan->max_tx;
|
||||
opts.txwin_size = (__u16)chan->tx_win;
|
||||
|
||||
len = min_t(unsigned int, len, sizeof(opts));
|
||||
if (copy_to_user(optval, (char *) &opts, len))
|
||||
@ -412,7 +423,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
|
||||
break;
|
||||
|
||||
case L2CAP_LM:
|
||||
switch (l2cap_pi(sk)->sec_level) {
|
||||
switch (chan->sec_level) {
|
||||
case BT_SECURITY_LOW:
|
||||
opt = L2CAP_LM_AUTH;
|
||||
break;
|
||||
@ -428,10 +439,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
|
||||
break;
|
||||
}
|
||||
|
||||
if (l2cap_pi(sk)->role_switch)
|
||||
if (chan->role_switch)
|
||||
opt |= L2CAP_LM_MASTER;
|
||||
|
||||
if (l2cap_pi(sk)->force_reliable)
|
||||
if (chan->force_reliable)
|
||||
opt |= L2CAP_LM_RELIABLE;
|
||||
|
||||
if (put_user(opt, (u32 __user *) optval))
|
||||
@ -446,8 +457,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
|
||||
break;
|
||||
}
|
||||
|
||||
cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle;
|
||||
memcpy(cinfo.dev_class, l2cap_pi(sk)->conn->hcon->dev_class, 3);
|
||||
cinfo.hci_handle = chan->conn->hcon->handle;
|
||||
memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3);
|
||||
|
||||
len = min_t(unsigned int, len, sizeof(cinfo));
|
||||
if (copy_to_user(optval, (char *) &cinfo, len))
|
||||
@ -467,6 +478,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
|
||||
static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
struct bt_security sec;
|
||||
int len, err = 0;
|
||||
|
||||
@ -491,7 +503,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
|
||||
break;
|
||||
}
|
||||
|
||||
sec.level = l2cap_pi(sk)->sec_level;
|
||||
sec.level = chan->sec_level;
|
||||
|
||||
len = min_t(unsigned int, len, sizeof(sec));
|
||||
if (copy_to_user(optval, (char *) &sec, len))
|
||||
@ -511,7 +523,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
|
||||
break;
|
||||
|
||||
case BT_FLUSHABLE:
|
||||
if (put_user(l2cap_pi(sk)->flushable, (u32 __user *) optval))
|
||||
if (put_user(chan->flushable, (u32 __user *) optval))
|
||||
err = -EFAULT;
|
||||
|
||||
break;
|
||||
@ -528,6 +540,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
|
||||
static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
struct l2cap_options opts;
|
||||
int len, err = 0;
|
||||
u32 opt;
|
||||
@ -543,13 +556,13 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
|
||||
break;
|
||||
}
|
||||
|
||||
opts.imtu = l2cap_pi(sk)->imtu;
|
||||
opts.omtu = l2cap_pi(sk)->omtu;
|
||||
opts.flush_to = l2cap_pi(sk)->flush_to;
|
||||
opts.mode = l2cap_pi(sk)->mode;
|
||||
opts.fcs = l2cap_pi(sk)->fcs;
|
||||
opts.max_tx = l2cap_pi(sk)->max_tx;
|
||||
opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win;
|
||||
opts.imtu = chan->imtu;
|
||||
opts.omtu = chan->omtu;
|
||||
opts.flush_to = chan->flush_to;
|
||||
opts.mode = chan->mode;
|
||||
opts.fcs = chan->fcs;
|
||||
opts.max_tx = chan->max_tx;
|
||||
opts.txwin_size = (__u16)chan->tx_win;
|
||||
|
||||
len = min_t(unsigned int, sizeof(opts), optlen);
|
||||
if (copy_from_user((char *) &opts, optval, len)) {
|
||||
@ -562,10 +575,10 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
|
||||
break;
|
||||
}
|
||||
|
||||
l2cap_pi(sk)->mode = opts.mode;
|
||||
switch (l2cap_pi(sk)->mode) {
|
||||
chan->mode = opts.mode;
|
||||
switch (chan->mode) {
|
||||
case L2CAP_MODE_BASIC:
|
||||
l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE;
|
||||
chan->conf_state &= ~L2CAP_CONF_STATE2_DEVICE;
|
||||
break;
|
||||
case L2CAP_MODE_ERTM:
|
||||
case L2CAP_MODE_STREAMING:
|
||||
@ -577,11 +590,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
|
||||
break;
|
||||
}
|
||||
|
||||
l2cap_pi(sk)->imtu = opts.imtu;
|
||||
l2cap_pi(sk)->omtu = opts.omtu;
|
||||
l2cap_pi(sk)->fcs = opts.fcs;
|
||||
l2cap_pi(sk)->max_tx = opts.max_tx;
|
||||
l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size;
|
||||
chan->imtu = opts.imtu;
|
||||
chan->omtu = opts.omtu;
|
||||
chan->fcs = opts.fcs;
|
||||
chan->max_tx = opts.max_tx;
|
||||
chan->tx_win = (__u8)opts.txwin_size;
|
||||
break;
|
||||
|
||||
case L2CAP_LM:
|
||||
@ -591,14 +604,14 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
|
||||
}
|
||||
|
||||
if (opt & L2CAP_LM_AUTH)
|
||||
l2cap_pi(sk)->sec_level = BT_SECURITY_LOW;
|
||||
chan->sec_level = BT_SECURITY_LOW;
|
||||
if (opt & L2CAP_LM_ENCRYPT)
|
||||
l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
|
||||
chan->sec_level = BT_SECURITY_MEDIUM;
|
||||
if (opt & L2CAP_LM_SECURE)
|
||||
l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH;
|
||||
chan->sec_level = BT_SECURITY_HIGH;
|
||||
|
||||
l2cap_pi(sk)->role_switch = (opt & L2CAP_LM_MASTER);
|
||||
l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE);
|
||||
chan->role_switch = (opt & L2CAP_LM_MASTER);
|
||||
chan->force_reliable = (opt & L2CAP_LM_RELIABLE);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -613,6 +626,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
|
||||
static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
struct bt_security sec;
|
||||
int len, err = 0;
|
||||
u32 opt;
|
||||
@ -649,7 +663,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
|
||||
break;
|
||||
}
|
||||
|
||||
l2cap_pi(sk)->sec_level = sec.level;
|
||||
chan->sec_level = sec.level;
|
||||
break;
|
||||
|
||||
case BT_DEFER_SETUP:
|
||||
@ -678,7 +692,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
|
||||
}
|
||||
|
||||
if (opt == BT_FLUSHABLE_OFF) {
|
||||
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
/* proceed futher only when we have l2cap_conn and
|
||||
No Flush support in the LM */
|
||||
if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) {
|
||||
@ -687,7 +701,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
|
||||
}
|
||||
}
|
||||
|
||||
l2cap_pi(sk)->flushable = opt;
|
||||
chan->flushable = opt;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -702,7 +716,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
|
||||
static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct l2cap_pinfo *pi = l2cap_pi(sk);
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
struct sk_buff *skb;
|
||||
u16 control;
|
||||
int err;
|
||||
@ -725,76 +739,77 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
|
||||
|
||||
/* Connectionless channel */
|
||||
if (sk->sk_type == SOCK_DGRAM) {
|
||||
skb = l2cap_create_connless_pdu(sk, msg, len);
|
||||
skb = l2cap_create_connless_pdu(chan, msg, len);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
} else {
|
||||
l2cap_do_send(sk, skb);
|
||||
l2cap_do_send(chan, skb);
|
||||
err = len;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (pi->mode) {
|
||||
switch (chan->mode) {
|
||||
case L2CAP_MODE_BASIC:
|
||||
/* Check outgoing MTU */
|
||||
if (len > pi->omtu) {
|
||||
if (len > chan->omtu) {
|
||||
err = -EMSGSIZE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Create a basic PDU */
|
||||
skb = l2cap_create_basic_pdu(sk, msg, len);
|
||||
skb = l2cap_create_basic_pdu(chan, msg, len);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
goto done;
|
||||
}
|
||||
|
||||
l2cap_do_send(sk, skb);
|
||||
l2cap_do_send(chan, skb);
|
||||
err = len;
|
||||
break;
|
||||
|
||||
case L2CAP_MODE_ERTM:
|
||||
case L2CAP_MODE_STREAMING:
|
||||
/* Entire SDU fits into one PDU */
|
||||
if (len <= pi->chan->remote_mps) {
|
||||
if (len <= chan->remote_mps) {
|
||||
control = L2CAP_SDU_UNSEGMENTED;
|
||||
skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0);
|
||||
skb = l2cap_create_iframe_pdu(chan, msg, len, control,
|
||||
0);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
goto done;
|
||||
}
|
||||
__skb_queue_tail(&pi->chan->tx_q, skb);
|
||||
__skb_queue_tail(&chan->tx_q, skb);
|
||||
|
||||
if (pi->chan->tx_send_head == NULL)
|
||||
pi->chan->tx_send_head = skb;
|
||||
if (chan->tx_send_head == NULL)
|
||||
chan->tx_send_head = skb;
|
||||
|
||||
} else {
|
||||
/* Segment SDU into multiples PDUs */
|
||||
err = l2cap_sar_segment_sdu(pi->chan, msg, len);
|
||||
err = l2cap_sar_segment_sdu(chan, msg, len);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (pi->mode == L2CAP_MODE_STREAMING) {
|
||||
l2cap_streaming_send(pi->chan);
|
||||
if (chan->mode == L2CAP_MODE_STREAMING) {
|
||||
l2cap_streaming_send(chan);
|
||||
err = len;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((pi->chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
|
||||
(pi->chan->conn_state & L2CAP_CONN_WAIT_F)) {
|
||||
if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
|
||||
(chan->conn_state & L2CAP_CONN_WAIT_F)) {
|
||||
err = len;
|
||||
break;
|
||||
}
|
||||
err = l2cap_ertm_send(pi->chan);
|
||||
err = l2cap_ertm_send(chan);
|
||||
|
||||
if (err >= 0)
|
||||
err = len;
|
||||
break;
|
||||
|
||||
default:
|
||||
BT_DBG("bad state %1.1x", pi->mode);
|
||||
BT_DBG("bad state %1.1x", chan->mode);
|
||||
err = -EBADFD;
|
||||
}
|
||||
|
||||
@ -810,7 +825,9 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
|
||||
lock_sock(sk);
|
||||
|
||||
if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
|
||||
__l2cap_connect_rsp_defer(sk);
|
||||
sk->sk_state = BT_CONFIG;
|
||||
|
||||
__l2cap_connect_rsp_defer(l2cap_pi(sk)->chan);
|
||||
release_sock(sk);
|
||||
return 0;
|
||||
}
|
||||
@ -834,6 +851,8 @@ void l2cap_sock_kill(struct sock *sk)
|
||||
BT_DBG("sk %p state %d", sk, sk->sk_state);
|
||||
|
||||
/* Kill poor orphan */
|
||||
|
||||
l2cap_chan_free(l2cap_pi(sk)->chan);
|
||||
bt_sock_unlink(&l2cap_sk_list, sk);
|
||||
sock_set_flag(sk, SOCK_DEAD);
|
||||
sock_put(sk);
|
||||
@ -865,8 +884,8 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
|
||||
|
||||
void __l2cap_sock_close(struct sock *sk, int reason)
|
||||
{
|
||||
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
|
||||
BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
|
||||
|
||||
@ -898,8 +917,8 @@ void __l2cap_sock_close(struct sock *sk, int reason)
|
||||
else
|
||||
result = L2CAP_CR_BAD_PSM;
|
||||
|
||||
rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
|
||||
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
|
||||
rsp.scid = cpu_to_le16(chan->dcid);
|
||||
rsp.dcid = cpu_to_le16(chan->scid);
|
||||
rsp.result = cpu_to_le16(result);
|
||||
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
|
||||
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
|
||||
@ -923,6 +942,7 @@ void __l2cap_sock_close(struct sock *sk, int reason)
|
||||
static int l2cap_sock_shutdown(struct socket *sock, int how)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
int err = 0;
|
||||
|
||||
BT_DBG("sock %p, sk %p", sock, sk);
|
||||
@ -932,7 +952,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
|
||||
|
||||
lock_sock(sk);
|
||||
if (!sk->sk_shutdown) {
|
||||
if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM)
|
||||
if (chan->mode == L2CAP_MODE_ERTM)
|
||||
err = __l2cap_wait_ack(sk);
|
||||
|
||||
sk->sk_shutdown = SHUTDOWN_MASK;
|
||||
@ -979,44 +999,47 @@ static void l2cap_sock_destruct(struct sock *sk)
|
||||
void l2cap_sock_init(struct sock *sk, struct sock *parent)
|
||||
{
|
||||
struct l2cap_pinfo *pi = l2cap_pi(sk);
|
||||
struct l2cap_chan *chan = pi->chan;
|
||||
|
||||
BT_DBG("sk %p", sk);
|
||||
|
||||
if (parent) {
|
||||
struct l2cap_chan *pchan = l2cap_pi(parent)->chan;
|
||||
|
||||
sk->sk_type = parent->sk_type;
|
||||
bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup;
|
||||
|
||||
pi->imtu = l2cap_pi(parent)->imtu;
|
||||
pi->omtu = l2cap_pi(parent)->omtu;
|
||||
pi->conf_state = l2cap_pi(parent)->conf_state;
|
||||
pi->mode = l2cap_pi(parent)->mode;
|
||||
pi->fcs = l2cap_pi(parent)->fcs;
|
||||
pi->max_tx = l2cap_pi(parent)->max_tx;
|
||||
pi->tx_win = l2cap_pi(parent)->tx_win;
|
||||
pi->sec_level = l2cap_pi(parent)->sec_level;
|
||||
pi->role_switch = l2cap_pi(parent)->role_switch;
|
||||
pi->force_reliable = l2cap_pi(parent)->force_reliable;
|
||||
pi->flushable = l2cap_pi(parent)->flushable;
|
||||
chan->imtu = pchan->imtu;
|
||||
chan->omtu = pchan->omtu;
|
||||
chan->conf_state = pchan->conf_state;
|
||||
chan->mode = pchan->mode;
|
||||
chan->fcs = pchan->fcs;
|
||||
chan->max_tx = pchan->max_tx;
|
||||
chan->tx_win = pchan->tx_win;
|
||||
chan->sec_level = pchan->sec_level;
|
||||
chan->role_switch = pchan->role_switch;
|
||||
chan->force_reliable = pchan->force_reliable;
|
||||
chan->flushable = pchan->flushable;
|
||||
} else {
|
||||
pi->imtu = L2CAP_DEFAULT_MTU;
|
||||
pi->omtu = 0;
|
||||
chan->imtu = L2CAP_DEFAULT_MTU;
|
||||
chan->omtu = 0;
|
||||
if (!disable_ertm && sk->sk_type == SOCK_STREAM) {
|
||||
pi->mode = L2CAP_MODE_ERTM;
|
||||
pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
|
||||
chan->mode = L2CAP_MODE_ERTM;
|
||||
chan->conf_state |= L2CAP_CONF_STATE2_DEVICE;
|
||||
} else {
|
||||
pi->mode = L2CAP_MODE_BASIC;
|
||||
chan->mode = L2CAP_MODE_BASIC;
|
||||
}
|
||||
pi->max_tx = L2CAP_DEFAULT_MAX_TX;
|
||||
pi->fcs = L2CAP_FCS_CRC16;
|
||||
pi->tx_win = L2CAP_DEFAULT_TX_WINDOW;
|
||||
pi->sec_level = BT_SECURITY_LOW;
|
||||
pi->role_switch = 0;
|
||||
pi->force_reliable = 0;
|
||||
pi->flushable = BT_FLUSHABLE_OFF;
|
||||
chan->max_tx = L2CAP_DEFAULT_MAX_TX;
|
||||
chan->fcs = L2CAP_FCS_CRC16;
|
||||
chan->tx_win = L2CAP_DEFAULT_TX_WINDOW;
|
||||
chan->sec_level = BT_SECURITY_LOW;
|
||||
chan->role_switch = 0;
|
||||
chan->force_reliable = 0;
|
||||
chan->flushable = BT_FLUSHABLE_OFF;
|
||||
}
|
||||
|
||||
/* Default config options */
|
||||
pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
|
||||
chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
|
||||
}
|
||||
|
||||
static struct proto l2cap_proto = {
|
||||
@ -1054,6 +1077,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
|
||||
int kern)
|
||||
{
|
||||
struct sock *sk;
|
||||
struct l2cap_chan *chan;
|
||||
|
||||
BT_DBG("sock %p", sock);
|
||||
|
||||
@ -1072,11 +1096,19 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
|
||||
if (!sk)
|
||||
return -ENOMEM;
|
||||
|
||||
chan = l2cap_chan_alloc(sk);
|
||||
if (!chan) {
|
||||
l2cap_sock_kill(sk);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
l2cap_pi(sk)->chan = chan;
|
||||
|
||||
l2cap_sock_init(sk, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct proto_ops l2cap_sock_ops = {
|
||||
static const struct proto_ops l2cap_sock_ops = {
|
||||
.family = PF_BLUETOOTH,
|
||||
.owner = THIS_MODULE,
|
||||
.release = l2cap_sock_release,
|
||||
|
@ -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++) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1569,6 +1569,75 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
|
||||
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)
|
||||
{
|
||||
unsigned char *buf;
|
||||
@ -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),
|
||||
len);
|
||||
break;
|
||||
|
||||
case MGMT_OP_START_DISCOVERY:
|
||||
err = start_discovery(sk, index);
|
||||
break;
|
||||
case MGMT_OP_STOP_DISCOVERY:
|
||||
err = stop_discovery(sk, index);
|
||||
break;
|
||||
default:
|
||||
BT_DBG("Unknown op %u", opcode);
|
||||
err = cmd_status(sk, index, opcode, 0x01);
|
||||
@ -1784,17 +1858,17 @@ int mgmt_connectable(u16 index, u8 connectable)
|
||||
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;
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
|
||||
ev.store_hint = persistent;
|
||||
bacpy(&ev.key.bdaddr, &key->bdaddr);
|
||||
ev.key.type = key->type;
|
||||
memcpy(ev.key.val, key->val, 16);
|
||||
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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
bacpy(&ev.bdaddr, bdaddr);
|
||||
ev.secure = secure;
|
||||
|
||||
return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
|
||||
NULL);
|
||||
@ -1920,13 +1995,15 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
|
||||
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;
|
||||
|
||||
BT_DBG("hci%u", index);
|
||||
|
||||
bacpy(&ev.bdaddr, bdaddr);
|
||||
ev.confirm_hint = confirm_hint;
|
||||
put_unaligned_le32(value, &ev.value);
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
static inline int rfcomm_check_security(struct rfcomm_dlc *d)
|
||||
{
|
||||
struct sock *sk = d->session->sock->sk;
|
||||
struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
|
||||
|
||||
__u8 auth_type;
|
||||
|
||||
switch (d->sec_level) {
|
||||
@ -246,8 +248,7 @@ static inline int rfcomm_check_security(struct rfcomm_dlc *d)
|
||||
break;
|
||||
}
|
||||
|
||||
return hci_conn_security(l2cap_pi(sk)->conn->hcon, d->sec_level,
|
||||
auth_type);
|
||||
return hci_conn_security(conn->hcon, d->sec_level, auth_type);
|
||||
}
|
||||
|
||||
static void rfcomm_session_timeout(unsigned long arg)
|
||||
@ -710,10 +711,10 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
|
||||
/* Set L2CAP options */
|
||||
sk = sock->sk;
|
||||
lock_sock(sk);
|
||||
l2cap_pi(sk)->imtu = l2cap_mtu;
|
||||
l2cap_pi(sk)->sec_level = sec_level;
|
||||
l2cap_pi(sk)->chan->imtu = l2cap_mtu;
|
||||
l2cap_pi(sk)->chan->sec_level = sec_level;
|
||||
if (l2cap_ertm)
|
||||
l2cap_pi(sk)->mode = L2CAP_MODE_ERTM;
|
||||
l2cap_pi(sk)->chan->mode = L2CAP_MODE_ERTM;
|
||||
release_sock(sk);
|
||||
|
||||
s = rfcomm_session_add(sock, BT_BOUND);
|
||||
@ -1241,6 +1242,7 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
|
||||
void rfcomm_dlc_accept(struct rfcomm_dlc *d)
|
||||
{
|
||||
struct sock *sk = d->session->sock->sk;
|
||||
struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
|
||||
|
||||
BT_DBG("dlc %p", d);
|
||||
|
||||
@ -1254,7 +1256,7 @@ void rfcomm_dlc_accept(struct rfcomm_dlc *d)
|
||||
rfcomm_dlc_unlock(d);
|
||||
|
||||
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);
|
||||
}
|
||||
@ -1890,7 +1892,8 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s)
|
||||
|
||||
/* We should adjust MTU on incoming sessions.
|
||||
* 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();
|
||||
} else
|
||||
@ -1909,7 +1912,7 @@ static inline void rfcomm_check_connection(struct rfcomm_session *s)
|
||||
|
||||
/* We can adjust MTU on outgoing sessions.
|
||||
* 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);
|
||||
break;
|
||||
@ -1992,7 +1995,7 @@ static int rfcomm_add_listener(bdaddr_t *ba)
|
||||
/* Set L2CAP options */
|
||||
sk = sock->sk;
|
||||
lock_sock(sk);
|
||||
l2cap_pi(sk)->imtu = l2cap_mtu;
|
||||
l2cap_pi(sk)->chan->imtu = l2cap_mtu;
|
||||
release_sock(sk);
|
||||
|
||||
/* Start listening on the socket */
|
||||
|
@ -743,6 +743,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
|
||||
struct sock *sk = sock->sk;
|
||||
struct sock *l2cap_sk;
|
||||
struct rfcomm_conninfo cinfo;
|
||||
struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
|
||||
int len, err = 0;
|
||||
u32 opt;
|
||||
|
||||
@ -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;
|
||||
|
||||
cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle;
|
||||
memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3);
|
||||
cinfo.hci_handle = conn->hcon->handle;
|
||||
memcpy(cinfo.dev_class, conn->hcon->dev_class, 3);
|
||||
|
||||
len = min_t(unsigned int, len, sizeof(cinfo));
|
||||
if (copy_to_user(optval, (char *) &cinfo, len))
|
||||
|
Loading…
Reference in New Issue
Block a user