Loading include/net/bluetooth/hci_core.h +25 −6 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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) Loading @@ -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: Loading @@ -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); Loading include/net/bluetooth/l2cap.h +1 −1 Original line number Diff line number Diff line Loading @@ -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, Loading net/bluetooth/hci_core.c +5 −0 Original line number Diff line number Diff line Loading @@ -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)); Loading Loading @@ -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); Loading net/bluetooth/hci_event.c +50 −6 Original line number Diff line number Diff line Loading @@ -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); } Loading Loading @@ -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)) { Loading @@ -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); Loading @@ -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); Loading @@ -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 */ Loading net/bluetooth/l2cap_core.c +51 −49 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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) Loading Loading @@ -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; } Loading Loading @@ -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: Loading Loading @@ -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 (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_NO_FCS_RECV, &chan->conf_state)) { 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); 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); break; case L2CAP_MODE_STREAMING: Loading @@ -3139,13 +3138,12 @@ 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->conn->feat_mask & L2CAP_FEAT_FCS) if (chan->fcs == L2CAP_FCS_NONE || test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) { 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); l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); } break; } Loading Loading @@ -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: Loading Loading @@ -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; } } Loading Loading @@ -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; } Loading Loading @@ -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; } Loading @@ -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); Loading Loading @@ -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; } Loading @@ -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; } Loading @@ -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; } Loading @@ -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; } Loading @@ -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); } Loading Loading @@ -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; } Loading Loading @@ -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); } Loading Loading @@ -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; } Loading @@ -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; } Loading Loading @@ -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; } Loading @@ -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; } Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; } Loading @@ -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, Loading @@ -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; } Loading @@ -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; Loading Loading
include/net/bluetooth/hci_core.h +25 −6 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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) Loading @@ -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: Loading @@ -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); Loading
include/net/bluetooth/l2cap.h +1 −1 Original line number Diff line number Diff line Loading @@ -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, Loading
net/bluetooth/hci_core.c +5 −0 Original line number Diff line number Diff line Loading @@ -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)); Loading Loading @@ -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); Loading
net/bluetooth/hci_event.c +50 −6 Original line number Diff line number Diff line Loading @@ -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); } Loading Loading @@ -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)) { Loading @@ -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); Loading @@ -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); Loading @@ -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 */ Loading
net/bluetooth/l2cap_core.c +51 −49 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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) Loading Loading @@ -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; } Loading Loading @@ -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: Loading Loading @@ -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 (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_NO_FCS_RECV, &chan->conf_state)) { 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); 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); break; case L2CAP_MODE_STREAMING: Loading @@ -3139,13 +3138,12 @@ 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->conn->feat_mask & L2CAP_FEAT_FCS) if (chan->fcs == L2CAP_FCS_NONE || test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) { 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); l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); } break; } Loading Loading @@ -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: Loading Loading @@ -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; } } Loading Loading @@ -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; } Loading Loading @@ -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; } Loading @@ -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); Loading Loading @@ -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; } Loading @@ -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; } Loading @@ -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; } Loading @@ -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; } Loading @@ -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); } Loading Loading @@ -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; } Loading Loading @@ -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); } Loading Loading @@ -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; } Loading @@ -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; } Loading Loading @@ -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; } Loading @@ -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; } Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; } Loading @@ -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, Loading @@ -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; } Loading @@ -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; Loading