Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
This commit is contained in:
commit
06ef5c4bbb
8 changed files with 213 additions and 81 deletions
|
@ -376,7 +376,7 @@ extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt);
|
|||
extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb,
|
||||
u16 flags);
|
||||
|
||||
extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags);
|
||||
extern void sco_connect_cfm(struct hci_conn *hcon, __u8 status);
|
||||
extern void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason);
|
||||
extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);
|
||||
|
@ -577,6 +577,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
|
|||
int hci_conn_del(struct hci_conn *conn);
|
||||
void hci_conn_hash_flush(struct hci_dev *hdev);
|
||||
void hci_conn_check_pending(struct hci_dev *hdev);
|
||||
void hci_conn_accept(struct hci_conn *conn, int mask);
|
||||
|
||||
struct hci_chan *hci_chan_create(struct hci_conn *conn);
|
||||
void hci_chan_del(struct hci_chan *chan);
|
||||
|
@ -766,7 +767,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
|
|||
#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
|
||||
#define lmp_pause_enc_capable(dev) ((dev)->features[5] & LMP_PAUSE_ENC)
|
||||
#define lmp_ext_inq_capable(dev) ((dev)->features[6] & LMP_EXT_INQ)
|
||||
#define lmp_le_br_capable(dev) ((dev)->features[6] & LMP_SIMUL_LE_BR)
|
||||
#define lmp_le_br_capable(dev) !!((dev)->features[6] & LMP_SIMUL_LE_BR)
|
||||
#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR)
|
||||
#define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH)
|
||||
#define lmp_lsto_capable(dev) ((dev)->features[7] & LMP_LSTO)
|
||||
|
@ -775,12 +776,30 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
|
|||
|
||||
/* ----- Extended LMP capabilities ----- */
|
||||
#define lmp_host_ssp_capable(dev) ((dev)->host_features[0] & LMP_HOST_SSP)
|
||||
#define lmp_host_le_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE)
|
||||
#define lmp_host_le_br_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE_BREDR)
|
||||
#define lmp_host_le_capable(dev) !!((dev)->host_features[0] & LMP_HOST_LE)
|
||||
#define lmp_host_le_br_capable(dev) !!((dev)->host_features[0] & LMP_HOST_LE_BREDR)
|
||||
|
||||
/* returns true if at least one AMP active */
|
||||
static inline bool hci_amp_capable(void)
|
||||
{
|
||||
struct hci_dev *hdev;
|
||||
bool ret = false;
|
||||
|
||||
read_lock(&hci_dev_list_lock);
|
||||
list_for_each_entry(hdev, &hci_dev_list, list)
|
||||
if (hdev->amp_type == HCI_AMP &&
|
||||
test_bit(HCI_UP, &hdev->flags))
|
||||
ret = true;
|
||||
read_unlock(&hci_dev_list_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ----- HCI protocols ----- */
|
||||
#define HCI_PROTO_DEFER 0x01
|
||||
|
||||
static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
__u8 type)
|
||||
__u8 type, __u8 *flags)
|
||||
{
|
||||
switch (type) {
|
||||
case ACL_LINK:
|
||||
|
@ -788,7 +807,7 @@ static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
|||
|
||||
case SCO_LINK:
|
||||
case ESCO_LINK:
|
||||
return sco_connect_ind(hdev, bdaddr);
|
||||
return sco_connect_ind(hdev, bdaddr, flags);
|
||||
|
||||
default:
|
||||
BT_ERR("unknown link type %d", type);
|
||||
|
|
|
@ -611,7 +611,7 @@ enum {
|
|||
CONF_MTU_DONE,
|
||||
CONF_MODE_DONE,
|
||||
CONF_CONNECT_PEND,
|
||||
CONF_NO_FCS_RECV,
|
||||
CONF_RECV_NO_FCS,
|
||||
CONF_STATE2_DEVICE,
|
||||
CONF_EWS_RECV,
|
||||
CONF_LOC_CONF_PEND,
|
||||
|
|
|
@ -861,6 +861,9 @@ static int hci_dev_do_close(struct hci_dev *hdev)
|
|||
/* Clear flags */
|
||||
hdev->flags = 0;
|
||||
|
||||
/* Controller radio is available but is currently powered down */
|
||||
hdev->amp_status = 0;
|
||||
|
||||
memset(hdev->eir, 0, sizeof(hdev->eir));
|
||||
memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
|
||||
|
||||
|
@ -1854,6 +1857,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
|
|||
for (i = 0; i < NUM_REASSEMBLY; i++)
|
||||
kfree_skb(hdev->reassembly[i]);
|
||||
|
||||
cancel_work_sync(&hdev->power_on);
|
||||
|
||||
if (!test_bit(HCI_INIT, &hdev->flags) &&
|
||||
!test_bit(HCI_SETUP, &hdev->dev_flags)) {
|
||||
hci_dev_lock(hdev);
|
||||
|
|
|
@ -794,10 +794,10 @@ static void hci_set_le_support(struct hci_dev *hdev)
|
|||
|
||||
if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
|
||||
cp.le = 1;
|
||||
cp.simul = !!lmp_le_br_capable(hdev);
|
||||
cp.simul = lmp_le_br_capable(hdev);
|
||||
}
|
||||
|
||||
if (cp.le != !!lmp_host_le_capable(hdev))
|
||||
if (cp.le != lmp_host_le_capable(hdev))
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
|
||||
&cp);
|
||||
}
|
||||
|
@ -2047,15 +2047,53 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hci_conn_check_pending(hdev);
|
||||
}
|
||||
|
||||
void hci_conn_accept(struct hci_conn *conn, int mask)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
conn->state = BT_CONFIG;
|
||||
|
||||
if (!lmp_esco_capable(hdev)) {
|
||||
struct hci_cp_accept_conn_req cp;
|
||||
|
||||
bacpy(&cp.bdaddr, &conn->dst);
|
||||
|
||||
if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
|
||||
cp.role = 0x00; /* Become master */
|
||||
else
|
||||
cp.role = 0x01; /* Remain slave */
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp);
|
||||
} else /* lmp_esco_capable(hdev)) */ {
|
||||
struct hci_cp_accept_sync_conn_req cp;
|
||||
|
||||
bacpy(&cp.bdaddr, &conn->dst);
|
||||
cp.pkt_type = cpu_to_le16(conn->pkt_type);
|
||||
|
||||
cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
||||
cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
||||
cp.max_latency = __constant_cpu_to_le16(0xffff);
|
||||
cp.content_format = cpu_to_le16(hdev->voice_setting);
|
||||
cp.retrans_effort = 0xff;
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
|
||||
sizeof(cp), &cp);
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_conn_request *ev = (void *) skb->data;
|
||||
int mask = hdev->link_mode;
|
||||
__u8 flags = 0;
|
||||
|
||||
BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr,
|
||||
ev->link_type);
|
||||
|
||||
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
|
||||
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type,
|
||||
&flags);
|
||||
|
||||
if ((mask & HCI_LM_ACCEPT) &&
|
||||
!hci_blacklist_lookup(hdev, &ev->bdaddr)) {
|
||||
|
@ -2081,12 +2119,13 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
memcpy(conn->dev_class, ev->dev_class, 3);
|
||||
conn->state = BT_CONNECT;
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
if (ev->link_type == ACL_LINK || !lmp_esco_capable(hdev)) {
|
||||
if (ev->link_type == ACL_LINK ||
|
||||
(!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) {
|
||||
struct hci_cp_accept_conn_req cp;
|
||||
conn->state = BT_CONNECT;
|
||||
|
||||
bacpy(&cp.bdaddr, &ev->bdaddr);
|
||||
|
||||
|
@ -2097,8 +2136,9 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
|
||||
hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp),
|
||||
&cp);
|
||||
} else {
|
||||
} else if (!(flags & HCI_PROTO_DEFER)) {
|
||||
struct hci_cp_accept_sync_conn_req cp;
|
||||
conn->state = BT_CONNECT;
|
||||
|
||||
bacpy(&cp.bdaddr, &ev->bdaddr);
|
||||
cp.pkt_type = cpu_to_le16(conn->pkt_type);
|
||||
|
@ -2111,6 +2151,10 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
|
||||
hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
|
||||
sizeof(cp), &cp);
|
||||
} else {
|
||||
conn->state = BT_CONNECT2;
|
||||
hci_proto_connect_cfm(conn, 0);
|
||||
hci_conn_put(conn);
|
||||
}
|
||||
} else {
|
||||
/* Connection rejected */
|
||||
|
|
|
@ -53,8 +53,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
|
|||
static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
|
||||
void *data);
|
||||
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
|
||||
static void l2cap_send_disconn_req(struct l2cap_conn *conn,
|
||||
struct l2cap_chan *chan, int err);
|
||||
static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err);
|
||||
|
||||
static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
|
||||
struct sk_buff_head *skbs, u8 event);
|
||||
|
@ -632,7 +631,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
|
|||
if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
|
||||
conn->hcon->type == ACL_LINK) {
|
||||
__set_chan_timer(chan, sk->sk_sndtimeo);
|
||||
l2cap_send_disconn_req(conn, chan, reason);
|
||||
l2cap_send_disconn_req(chan, reason);
|
||||
} else
|
||||
l2cap_chan_del(chan, reason);
|
||||
break;
|
||||
|
@ -1014,6 +1013,7 @@ static bool __amp_capable(struct l2cap_chan *chan)
|
|||
struct l2cap_conn *conn = chan->conn;
|
||||
|
||||
if (enable_hs &&
|
||||
hci_amp_capable() &&
|
||||
chan->chan_policy == BT_CHANNEL_POLICY_AMP_PREFERRED &&
|
||||
conn->fixed_chan_mask & L2CAP_FC_A2MP)
|
||||
return true;
|
||||
|
@ -1180,10 +1180,10 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
|
|||
}
|
||||
}
|
||||
|
||||
static void l2cap_send_disconn_req(struct l2cap_conn *conn,
|
||||
struct l2cap_chan *chan, int err)
|
||||
static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err)
|
||||
{
|
||||
struct sock *sk = chan->sk;
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
struct l2cap_disconn_req req;
|
||||
|
||||
if (!conn)
|
||||
|
@ -1960,7 +1960,7 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan)
|
|||
if (chan->max_tx != 0 &&
|
||||
bt_cb(skb)->control.retries > chan->max_tx) {
|
||||
BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
|
||||
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
l2cap_seq_list_clear(&chan->retrans_list);
|
||||
break;
|
||||
}
|
||||
|
@ -2666,7 +2666,7 @@ static void l2cap_tx_state_wait_f(struct l2cap_chan *chan,
|
|||
__set_monitor_timer(chan);
|
||||
chan->retry_count++;
|
||||
} else {
|
||||
l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
|
||||
l2cap_send_disconn_req(chan, ECONNABORTED);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -3106,18 +3106,17 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
|
|||
if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
|
||||
l2cap_add_opt_efs(&ptr, chan);
|
||||
|
||||
if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
|
||||
break;
|
||||
|
||||
if (chan->fcs == L2CAP_FCS_NONE ||
|
||||
test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
|
||||
chan->fcs = L2CAP_FCS_NONE;
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
|
||||
}
|
||||
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
|
||||
chan->tx_win);
|
||||
|
||||
if (chan->conn->feat_mask & L2CAP_FEAT_FCS)
|
||||
if (chan->fcs == L2CAP_FCS_NONE ||
|
||||
test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) {
|
||||
chan->fcs = L2CAP_FCS_NONE;
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1,
|
||||
chan->fcs);
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_MODE_STREAMING:
|
||||
|
@ -3139,14 +3138,13 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
|
|||
if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
|
||||
l2cap_add_opt_efs(&ptr, chan);
|
||||
|
||||
if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
|
||||
break;
|
||||
|
||||
if (chan->fcs == L2CAP_FCS_NONE ||
|
||||
test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
|
||||
chan->fcs = L2CAP_FCS_NONE;
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
|
||||
}
|
||||
if (chan->conn->feat_mask & L2CAP_FEAT_FCS)
|
||||
if (chan->fcs == L2CAP_FCS_NONE ||
|
||||
test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) {
|
||||
chan->fcs = L2CAP_FCS_NONE;
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1,
|
||||
chan->fcs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3198,7 +3196,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
|
|||
|
||||
case L2CAP_CONF_FCS:
|
||||
if (val == L2CAP_FCS_NONE)
|
||||
set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
|
||||
set_bit(CONF_RECV_NO_FCS, &chan->conf_state);
|
||||
break;
|
||||
|
||||
case L2CAP_CONF_EFS:
|
||||
|
@ -3433,6 +3431,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
|
|||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs),
|
||||
(unsigned long) &efs);
|
||||
break;
|
||||
|
||||
case L2CAP_CONF_FCS:
|
||||
if (*result == L2CAP_CONF_PENDING)
|
||||
if (val == L2CAP_FCS_NONE)
|
||||
set_bit(CONF_RECV_NO_FCS,
|
||||
&chan->conf_state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3802,7 +3807,7 @@ static inline void set_default_fcs(struct l2cap_chan *chan)
|
|||
*/
|
||||
if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
|
||||
chan->fcs = L2CAP_FCS_NONE;
|
||||
else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
|
||||
else if (!test_bit(CONF_RECV_NO_FCS, &chan->conf_state))
|
||||
chan->fcs = L2CAP_FCS_CRC16;
|
||||
}
|
||||
|
||||
|
@ -3877,7 +3882,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
|
|||
/* Complete config. */
|
||||
len = l2cap_parse_conf_req(chan, rsp);
|
||||
if (len < 0) {
|
||||
l2cap_send_disconn_req(conn, chan, ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
|
@ -3899,7 +3904,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
|
|||
err = l2cap_ertm_init(chan);
|
||||
|
||||
if (err < 0)
|
||||
l2cap_send_disconn_req(chan->conn, chan, -err);
|
||||
l2cap_send_disconn_req(chan, -err);
|
||||
else
|
||||
l2cap_chan_ready(chan);
|
||||
|
||||
|
@ -3967,7 +3972,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
|||
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
|
||||
buf, &result);
|
||||
if (len < 0) {
|
||||
l2cap_send_disconn_req(conn, chan, ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -3988,7 +3993,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
|||
char req[64];
|
||||
|
||||
if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
|
||||
l2cap_send_disconn_req(conn, chan, ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -3997,7 +4002,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
|||
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
|
||||
req, &result);
|
||||
if (len < 0) {
|
||||
l2cap_send_disconn_req(conn, chan, ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -4013,7 +4018,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
|||
l2cap_chan_set_err(chan, ECONNRESET);
|
||||
|
||||
__set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
|
||||
l2cap_send_disconn_req(conn, chan, ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -4030,7 +4035,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
|||
err = l2cap_ertm_init(chan);
|
||||
|
||||
if (err < 0)
|
||||
l2cap_send_disconn_req(chan->conn, chan, -err);
|
||||
l2cap_send_disconn_req(chan, -err);
|
||||
else
|
||||
l2cap_chan_ready(chan);
|
||||
}
|
||||
|
@ -4392,7 +4397,7 @@ static void l2cap_logical_fail(struct l2cap_chan *chan)
|
|||
/* Logical link setup failed */
|
||||
if (chan->state != BT_CONNECTED) {
|
||||
/* Create channel failure, disconnect */
|
||||
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4435,7 +4440,7 @@ static void l2cap_logical_finish_create(struct l2cap_chan *chan,
|
|||
|
||||
err = l2cap_ertm_init(chan);
|
||||
if (err < 0)
|
||||
l2cap_send_disconn_req(chan->conn, chan, -err);
|
||||
l2cap_send_disconn_req(chan, -err);
|
||||
else
|
||||
l2cap_chan_ready(chan);
|
||||
}
|
||||
|
@ -5400,7 +5405,7 @@ static void l2cap_handle_srej(struct l2cap_chan *chan,
|
|||
|
||||
if (control->reqseq == chan->next_tx_seq) {
|
||||
BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq);
|
||||
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -5414,7 +5419,7 @@ static void l2cap_handle_srej(struct l2cap_chan *chan,
|
|||
|
||||
if (chan->max_tx != 0 && bt_cb(skb)->control.retries >= chan->max_tx) {
|
||||
BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
|
||||
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -5458,7 +5463,7 @@ static void l2cap_handle_rej(struct l2cap_chan *chan,
|
|||
|
||||
if (control->reqseq == chan->next_tx_seq) {
|
||||
BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq);
|
||||
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -5467,7 +5472,7 @@ static void l2cap_handle_rej(struct l2cap_chan *chan,
|
|||
if (chan->max_tx && skb &&
|
||||
bt_cb(skb)->control.retries >= chan->max_tx) {
|
||||
BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
|
||||
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -5651,8 +5656,7 @@ static int l2cap_rx_state_recv(struct l2cap_chan *chan,
|
|||
break;
|
||||
case L2CAP_TXSEQ_INVALID:
|
||||
default:
|
||||
l2cap_send_disconn_req(chan->conn, chan,
|
||||
ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -5785,8 +5789,7 @@ static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan,
|
|||
break;
|
||||
case L2CAP_TXSEQ_INVALID:
|
||||
default:
|
||||
l2cap_send_disconn_req(chan->conn, chan,
|
||||
ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -5981,7 +5984,7 @@ static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
|
|||
BT_DBG("Invalid reqseq %d (next_tx_seq %d, expected_ack_seq %d",
|
||||
control->reqseq, chan->next_tx_seq,
|
||||
chan->expected_ack_seq);
|
||||
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -6050,7 +6053,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|||
len -= L2CAP_FCS_SIZE;
|
||||
|
||||
if (len > chan->mps) {
|
||||
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
|
@ -6075,8 +6078,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
if (err)
|
||||
l2cap_send_disconn_req(chan->conn, chan,
|
||||
ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
} else {
|
||||
const u8 rx_func_to_event[4] = {
|
||||
L2CAP_EV_RECV_RR, L2CAP_EV_RECV_REJ,
|
||||
|
@ -6093,7 +6095,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|||
|
||||
if (len != 0) {
|
||||
BT_ERR("Trailing bytes: %d in sframe", len);
|
||||
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
|
@ -6104,7 +6106,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|||
|
||||
event = rx_func_to_event[control->super];
|
||||
if (l2cap_rx(chan, control, skb, event))
|
||||
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1226,7 +1226,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
|
|||
}
|
||||
|
||||
val = !!cp->val;
|
||||
enabled = !!lmp_host_le_capable(hdev);
|
||||
enabled = lmp_host_le_capable(hdev);
|
||||
|
||||
if (!hdev_is_powered(hdev) || val == enabled) {
|
||||
bool changed = false;
|
||||
|
@ -1262,7 +1262,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
|
|||
|
||||
if (val) {
|
||||
hci_cp.le = val;
|
||||
hci_cp.simul = !!lmp_le_br_capable(hdev);
|
||||
hci_cp.simul = lmp_le_br_capable(hdev);
|
||||
}
|
||||
|
||||
err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
|
||||
|
@ -2926,13 +2926,13 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered)
|
|||
struct hci_cp_write_le_host_supported cp;
|
||||
|
||||
cp.le = 1;
|
||||
cp.simul = !!lmp_le_br_capable(hdev);
|
||||
cp.simul = lmp_le_br_capable(hdev);
|
||||
|
||||
/* Check first if we already have the right
|
||||
* host state (host features set)
|
||||
*/
|
||||
if (cp.le != !!lmp_host_le_capable(hdev) ||
|
||||
cp.simul != !!lmp_host_le_br_capable(hdev))
|
||||
if (cp.le != lmp_host_le_capable(hdev) ||
|
||||
cp.simul != lmp_host_le_br_capable(hdev))
|
||||
hci_send_cmd(hdev,
|
||||
HCI_OP_WRITE_LE_HOST_SUPPORTED,
|
||||
sizeof(cp), &cp);
|
||||
|
|
|
@ -467,7 +467,7 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
|
|||
long timeo;
|
||||
int err = 0;
|
||||
|
||||
lock_sock(sk);
|
||||
lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
|
||||
|
||||
if (sk->sk_type != SOCK_STREAM) {
|
||||
err = -EINVAL;
|
||||
|
@ -504,7 +504,7 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
|
|||
|
||||
release_sock(sk);
|
||||
timeo = schedule_timeout(timeo);
|
||||
lock_sock(sk);
|
||||
lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
|
||||
}
|
||||
__set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(sk_sleep(sk), &wait);
|
||||
|
|
|
@ -131,15 +131,6 @@ static int sco_conn_del(struct hci_conn *hcon, int err)
|
|||
sco_sock_clear_timer(sk);
|
||||
sco_chan_del(sk, err);
|
||||
bh_unlock_sock(sk);
|
||||
|
||||
sco_conn_lock(conn);
|
||||
conn->sk = NULL;
|
||||
sco_pi(sk)->conn = NULL;
|
||||
sco_conn_unlock(conn);
|
||||
|
||||
if (conn->hcon)
|
||||
hci_conn_put(conn->hcon);
|
||||
|
||||
sco_sock_kill(sk);
|
||||
}
|
||||
|
||||
|
@ -397,6 +388,7 @@ static void sco_sock_init(struct sock *sk, struct sock *parent)
|
|||
|
||||
if (parent) {
|
||||
sk->sk_type = parent->sk_type;
|
||||
bt_sk(sk)->flags = bt_sk(parent)->flags;
|
||||
security_sk_clone(parent, sk);
|
||||
}
|
||||
}
|
||||
|
@ -662,16 +654,57 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||
struct msghdr *msg, size_t len, int flags)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct sco_pinfo *pi = sco_pi(sk);
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
if (sk->sk_state == BT_CONNECT2 &&
|
||||
test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
|
||||
hci_conn_accept(pi->conn->hcon, 0);
|
||||
sk->sk_state = BT_CONFIG;
|
||||
|
||||
release_sock(sk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
release_sock(sk);
|
||||
|
||||
return bt_sock_recvmsg(iocb, sock, msg, len, flags);
|
||||
}
|
||||
|
||||
static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
int err = 0;
|
||||
u32 opt;
|
||||
|
||||
BT_DBG("sk %p", sk);
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
switch (optname) {
|
||||
|
||||
case BT_DEFER_SETUP:
|
||||
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (get_user(opt, (u32 __user *) optval)) {
|
||||
err = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (opt)
|
||||
set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
|
||||
else
|
||||
clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -ENOPROTOOPT;
|
||||
break;
|
||||
|
@ -753,6 +786,19 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char
|
|||
lock_sock(sk);
|
||||
|
||||
switch (optname) {
|
||||
|
||||
case BT_DEFER_SETUP:
|
||||
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags),
|
||||
(u32 __user *) optval))
|
||||
err = -EFAULT;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -ENOPROTOOPT;
|
||||
break;
|
||||
|
@ -830,6 +876,16 @@ static void sco_chan_del(struct sock *sk, int err)
|
|||
|
||||
BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
|
||||
|
||||
if (conn) {
|
||||
sco_conn_lock(conn);
|
||||
conn->sk = NULL;
|
||||
sco_pi(sk)->conn = NULL;
|
||||
sco_conn_unlock(conn);
|
||||
|
||||
if (conn->hcon)
|
||||
hci_conn_put(conn->hcon);
|
||||
}
|
||||
|
||||
sk->sk_state = BT_CLOSED;
|
||||
sk->sk_err = err;
|
||||
sk->sk_state_change(sk);
|
||||
|
@ -874,7 +930,10 @@ static void sco_conn_ready(struct sco_conn *conn)
|
|||
hci_conn_hold(conn->hcon);
|
||||
__sco_chan_add(conn, sk, parent);
|
||||
|
||||
sk->sk_state = BT_CONNECTED;
|
||||
if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags))
|
||||
sk->sk_state = BT_CONNECT2;
|
||||
else
|
||||
sk->sk_state = BT_CONNECTED;
|
||||
|
||||
/* Wake up parent */
|
||||
parent->sk_data_ready(parent, 1);
|
||||
|
@ -887,7 +946,7 @@ static void sco_conn_ready(struct sco_conn *conn)
|
|||
}
|
||||
|
||||
/* ----- SCO interface with lower layer (HCI) ----- */
|
||||
int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
||||
int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
||||
{
|
||||
struct sock *sk;
|
||||
struct hlist_node *node;
|
||||
|
@ -904,6 +963,9 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
|||
if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) ||
|
||||
!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
|
||||
lm |= HCI_LM_ACCEPT;
|
||||
|
||||
if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))
|
||||
*flags |= HCI_PROTO_DEFER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -992,7 +1054,7 @@ static const struct proto_ops sco_sock_ops = {
|
|||
.accept = sco_sock_accept,
|
||||
.getname = sco_sock_getname,
|
||||
.sendmsg = sco_sock_sendmsg,
|
||||
.recvmsg = bt_sock_recvmsg,
|
||||
.recvmsg = sco_sock_recvmsg,
|
||||
.poll = bt_sock_poll,
|
||||
.ioctl = bt_sock_ioctl,
|
||||
.mmap = sock_no_mmap,
|
||||
|
|
Loading…
Reference in a new issue