diff options
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/amp.c | 8 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 98 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 44 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 52 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 2 |
5 files changed, 177 insertions, 27 deletions
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 4b2fea6c1c2a..1b0d92c0643a 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c | |||
@@ -386,13 +386,17 @@ void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon) | |||
386 | 386 | ||
387 | bredr_chan = mgr->bredr_chan; | 387 | bredr_chan = mgr->bredr_chan; |
388 | 388 | ||
389 | l2cap_chan_lock(bredr_chan); | ||
390 | |||
389 | set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags); | 391 | set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags); |
390 | bredr_chan->remote_amp_id = hs_hcon->remote_id; | 392 | bredr_chan->remote_amp_id = hs_hcon->remote_id; |
393 | bredr_chan->local_amp_id = hs_hcon->hdev->id; | ||
391 | bredr_chan->hs_hcon = hs_hcon; | 394 | bredr_chan->hs_hcon = hs_hcon; |
392 | bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu; | 395 | bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu; |
393 | bredr_chan->fcs = L2CAP_FCS_NONE; | ||
394 | 396 | ||
395 | l2cap_physical_cfm(bredr_chan, 0); | 397 | __l2cap_physical_cfm(bredr_chan, 0); |
398 | |||
399 | l2cap_chan_unlock(bredr_chan); | ||
396 | 400 | ||
397 | hci_dev_put(bredr_hdev); | 401 | hci_dev_put(bredr_hdev); |
398 | } | 402 | } |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c68c4098da98..7140f83328a2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -434,6 +434,8 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, | |||
434 | 434 | ||
435 | BT_DBG("cache %p, %pMR", cache, &data->bdaddr); | 435 | BT_DBG("cache %p, %pMR", cache, &data->bdaddr); |
436 | 436 | ||
437 | hci_remove_remote_oob_data(hdev, &data->bdaddr); | ||
438 | |||
437 | if (ssp) | 439 | if (ssp) |
438 | *ssp = data->ssp_mode; | 440 | *ssp = data->ssp_mode; |
439 | 441 | ||
@@ -594,6 +596,99 @@ done: | |||
594 | return err; | 596 | return err; |
595 | } | 597 | } |
596 | 598 | ||
599 | static u8 create_ad(struct hci_dev *hdev, u8 *ptr) | ||
600 | { | ||
601 | u8 ad_len = 0, flags = 0; | ||
602 | size_t name_len; | ||
603 | |||
604 | if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) | ||
605 | flags |= LE_AD_GENERAL; | ||
606 | |||
607 | if (!lmp_bredr_capable(hdev)) | ||
608 | flags |= LE_AD_NO_BREDR; | ||
609 | |||
610 | if (lmp_le_br_capable(hdev)) | ||
611 | flags |= LE_AD_SIM_LE_BREDR_CTRL; | ||
612 | |||
613 | if (lmp_host_le_br_capable(hdev)) | ||
614 | flags |= LE_AD_SIM_LE_BREDR_HOST; | ||
615 | |||
616 | if (flags) { | ||
617 | BT_DBG("adv flags 0x%02x", flags); | ||
618 | |||
619 | ptr[0] = 2; | ||
620 | ptr[1] = EIR_FLAGS; | ||
621 | ptr[2] = flags; | ||
622 | |||
623 | ad_len += 3; | ||
624 | ptr += 3; | ||
625 | } | ||
626 | |||
627 | if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) { | ||
628 | ptr[0] = 2; | ||
629 | ptr[1] = EIR_TX_POWER; | ||
630 | ptr[2] = (u8) hdev->adv_tx_power; | ||
631 | |||
632 | ad_len += 3; | ||
633 | ptr += 3; | ||
634 | } | ||
635 | |||
636 | name_len = strlen(hdev->dev_name); | ||
637 | if (name_len > 0) { | ||
638 | size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2; | ||
639 | |||
640 | if (name_len > max_len) { | ||
641 | name_len = max_len; | ||
642 | ptr[1] = EIR_NAME_SHORT; | ||
643 | } else | ||
644 | ptr[1] = EIR_NAME_COMPLETE; | ||
645 | |||
646 | ptr[0] = name_len + 1; | ||
647 | |||
648 | memcpy(ptr + 2, hdev->dev_name, name_len); | ||
649 | |||
650 | ad_len += (name_len + 2); | ||
651 | ptr += (name_len + 2); | ||
652 | } | ||
653 | |||
654 | return ad_len; | ||
655 | } | ||
656 | |||
657 | int hci_update_ad(struct hci_dev *hdev) | ||
658 | { | ||
659 | struct hci_cp_le_set_adv_data cp; | ||
660 | u8 len; | ||
661 | int err; | ||
662 | |||
663 | hci_dev_lock(hdev); | ||
664 | |||
665 | if (!lmp_le_capable(hdev)) { | ||
666 | err = -EINVAL; | ||
667 | goto unlock; | ||
668 | } | ||
669 | |||
670 | memset(&cp, 0, sizeof(cp)); | ||
671 | |||
672 | len = create_ad(hdev, cp.data); | ||
673 | |||
674 | if (hdev->adv_data_len == len && | ||
675 | memcmp(cp.data, hdev->adv_data, len) == 0) { | ||
676 | err = 0; | ||
677 | goto unlock; | ||
678 | } | ||
679 | |||
680 | memcpy(hdev->adv_data, cp.data, sizeof(cp.data)); | ||
681 | hdev->adv_data_len = len; | ||
682 | |||
683 | cp.length = len; | ||
684 | err = hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); | ||
685 | |||
686 | unlock: | ||
687 | hci_dev_unlock(hdev); | ||
688 | |||
689 | return err; | ||
690 | } | ||
691 | |||
597 | /* ---- HCI ioctl helpers ---- */ | 692 | /* ---- HCI ioctl helpers ---- */ |
598 | 693 | ||
599 | int hci_dev_open(__u16 dev) | 694 | int hci_dev_open(__u16 dev) |
@@ -651,6 +746,7 @@ int hci_dev_open(__u16 dev) | |||
651 | hci_dev_hold(hdev); | 746 | hci_dev_hold(hdev); |
652 | set_bit(HCI_UP, &hdev->flags); | 747 | set_bit(HCI_UP, &hdev->flags); |
653 | hci_notify(hdev, HCI_DEV_UP); | 748 | hci_notify(hdev, HCI_DEV_UP); |
749 | hci_update_ad(hdev); | ||
654 | if (!test_bit(HCI_SETUP, &hdev->dev_flags) && | 750 | if (!test_bit(HCI_SETUP, &hdev->dev_flags) && |
655 | mgmt_valid_hdev(hdev)) { | 751 | mgmt_valid_hdev(hdev)) { |
656 | hci_dev_lock(hdev); | 752 | hci_dev_lock(hdev); |
@@ -1606,6 +1702,8 @@ struct hci_dev *hci_alloc_dev(void) | |||
1606 | hdev->esco_type = (ESCO_HV1); | 1702 | hdev->esco_type = (ESCO_HV1); |
1607 | hdev->link_mode = (HCI_LM_ACCEPT); | 1703 | hdev->link_mode = (HCI_LM_ACCEPT); |
1608 | hdev->io_capability = 0x03; /* No Input No Output */ | 1704 | hdev->io_capability = 0x03; /* No Input No Output */ |
1705 | hdev->inq_tx_power = HCI_TX_POWER_INVALID; | ||
1706 | hdev->adv_tx_power = HCI_TX_POWER_INVALID; | ||
1609 | 1707 | ||
1610 | hdev->sniff_max_interval = 800; | 1708 | hdev->sniff_max_interval = 800; |
1611 | hdev->sniff_min_interval = 80; | 1709 | hdev->sniff_min_interval = 80; |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c08ac7c03711..9f5c5f244502 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -202,6 +202,11 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) | |||
202 | BIT(HCI_PERIODIC_INQ)); | 202 | BIT(HCI_PERIODIC_INQ)); |
203 | 203 | ||
204 | hdev->discovery.state = DISCOVERY_STOPPED; | 204 | hdev->discovery.state = DISCOVERY_STOPPED; |
205 | hdev->inq_tx_power = HCI_TX_POWER_INVALID; | ||
206 | hdev->adv_tx_power = HCI_TX_POWER_INVALID; | ||
207 | |||
208 | memset(hdev->adv_data, 0, sizeof(hdev->adv_data)); | ||
209 | hdev->adv_data_len = 0; | ||
205 | } | 210 | } |
206 | 211 | ||
207 | static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) | 212 | static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) |
@@ -224,6 +229,9 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) | |||
224 | 229 | ||
225 | hci_dev_unlock(hdev); | 230 | hci_dev_unlock(hdev); |
226 | 231 | ||
232 | if (!status && !test_bit(HCI_INIT, &hdev->flags)) | ||
233 | hci_update_ad(hdev); | ||
234 | |||
227 | hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status); | 235 | hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status); |
228 | } | 236 | } |
229 | 237 | ||
@@ -1089,8 +1097,11 @@ static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, | |||
1089 | 1097 | ||
1090 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); | 1098 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); |
1091 | 1099 | ||
1092 | if (!rp->status) | 1100 | if (!rp->status) { |
1093 | hdev->adv_tx_power = rp->tx_power; | 1101 | hdev->adv_tx_power = rp->tx_power; |
1102 | if (!test_bit(HCI_INIT, &hdev->flags)) | ||
1103 | hci_update_ad(hdev); | ||
1104 | } | ||
1094 | 1105 | ||
1095 | hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status); | 1106 | hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status); |
1096 | } | 1107 | } |
@@ -1179,6 +1190,33 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev, | |||
1179 | hci_dev_unlock(hdev); | 1190 | hci_dev_unlock(hdev); |
1180 | } | 1191 | } |
1181 | 1192 | ||
1193 | static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) | ||
1194 | { | ||
1195 | __u8 *sent, status = *((__u8 *) skb->data); | ||
1196 | |||
1197 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | ||
1198 | |||
1199 | sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_ENABLE); | ||
1200 | if (!sent) | ||
1201 | return; | ||
1202 | |||
1203 | hci_dev_lock(hdev); | ||
1204 | |||
1205 | if (!status) { | ||
1206 | if (*sent) | ||
1207 | set_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags); | ||
1208 | else | ||
1209 | clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags); | ||
1210 | } | ||
1211 | |||
1212 | hci_dev_unlock(hdev); | ||
1213 | |||
1214 | if (!test_bit(HCI_INIT, &hdev->flags)) | ||
1215 | hci_update_ad(hdev); | ||
1216 | |||
1217 | hci_req_complete(hdev, HCI_OP_LE_SET_ADV_ENABLE, status); | ||
1218 | } | ||
1219 | |||
1182 | static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) | 1220 | static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) |
1183 | { | 1221 | { |
1184 | __u8 status = *((__u8 *) skb->data); | 1222 | __u8 status = *((__u8 *) skb->data); |
@@ -2574,6 +2612,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
2574 | hci_cc_le_set_scan_param(hdev, skb); | 2612 | hci_cc_le_set_scan_param(hdev, skb); |
2575 | break; | 2613 | break; |
2576 | 2614 | ||
2615 | case HCI_OP_LE_SET_ADV_ENABLE: | ||
2616 | hci_cc_le_set_adv_enable(hdev, skb); | ||
2617 | break; | ||
2618 | |||
2577 | case HCI_OP_LE_SET_SCAN_ENABLE: | 2619 | case HCI_OP_LE_SET_SCAN_ENABLE: |
2578 | hci_cc_le_set_scan_enable(hdev, skb); | 2620 | hci_cc_le_set_scan_enable(hdev, skb); |
2579 | break; | 2621 | break; |
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a1faaab41839..b52f66d22437 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -4284,9 +4284,9 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn, | |||
4284 | 4284 | ||
4285 | BT_DBG("mgr %p bredr_chan %p hs_hcon %p", mgr, chan, hs_hcon); | 4285 | BT_DBG("mgr %p bredr_chan %p hs_hcon %p", mgr, chan, hs_hcon); |
4286 | 4286 | ||
4287 | chan->local_amp_id = req->amp_id; | ||
4288 | mgr->bredr_chan = chan; | 4287 | mgr->bredr_chan = chan; |
4289 | chan->hs_hcon = hs_hcon; | 4288 | chan->hs_hcon = hs_hcon; |
4289 | chan->fcs = L2CAP_FCS_NONE; | ||
4290 | conn->mtu = hdev->block_mtu; | 4290 | conn->mtu = hdev->block_mtu; |
4291 | } | 4291 | } |
4292 | 4292 | ||
@@ -4518,21 +4518,39 @@ void l2cap_move_start(struct l2cap_chan *chan) | |||
4518 | static void l2cap_do_create(struct l2cap_chan *chan, int result, | 4518 | static void l2cap_do_create(struct l2cap_chan *chan, int result, |
4519 | u8 local_amp_id, u8 remote_amp_id) | 4519 | u8 local_amp_id, u8 remote_amp_id) |
4520 | { | 4520 | { |
4521 | if (!test_bit(CONF_CONNECT_PEND, &chan->conf_state)) { | 4521 | BT_DBG("chan %p state %s %u -> %u", chan, state_to_string(chan->state), |
4522 | local_amp_id, remote_amp_id); | ||
4523 | |||
4524 | chan->fcs = L2CAP_FCS_NONE; | ||
4525 | |||
4526 | /* Outgoing channel on AMP */ | ||
4527 | if (chan->state == BT_CONNECT) { | ||
4528 | if (result == L2CAP_CR_SUCCESS) { | ||
4529 | chan->local_amp_id = local_amp_id; | ||
4530 | l2cap_send_create_chan_req(chan, remote_amp_id); | ||
4531 | } else { | ||
4532 | /* Revert to BR/EDR connect */ | ||
4533 | l2cap_send_conn_req(chan); | ||
4534 | } | ||
4535 | |||
4536 | return; | ||
4537 | } | ||
4538 | |||
4539 | /* Incoming channel on AMP */ | ||
4540 | if (__l2cap_no_conn_pending(chan)) { | ||
4522 | struct l2cap_conn_rsp rsp; | 4541 | struct l2cap_conn_rsp rsp; |
4523 | char buf[128]; | 4542 | char buf[128]; |
4524 | rsp.scid = cpu_to_le16(chan->dcid); | 4543 | rsp.scid = cpu_to_le16(chan->dcid); |
4525 | rsp.dcid = cpu_to_le16(chan->scid); | 4544 | rsp.dcid = cpu_to_le16(chan->scid); |
4526 | 4545 | ||
4527 | /* Incoming channel on AMP */ | ||
4528 | if (result == L2CAP_CR_SUCCESS) { | 4546 | if (result == L2CAP_CR_SUCCESS) { |
4529 | /* Send successful response */ | 4547 | /* Send successful response */ |
4530 | rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); | 4548 | rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); |
4531 | rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); | 4549 | rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); |
4532 | } else { | 4550 | } else { |
4533 | /* Send negative response */ | 4551 | /* Send negative response */ |
4534 | rsp.result = cpu_to_le16(L2CAP_CR_NO_MEM); | 4552 | rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM); |
4535 | rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); | 4553 | rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); |
4536 | } | 4554 | } |
4537 | 4555 | ||
4538 | l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_RSP, | 4556 | l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_RSP, |
@@ -4546,15 +4564,6 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result, | |||
4546 | l2cap_build_conf_req(chan, buf), buf); | 4564 | l2cap_build_conf_req(chan, buf), buf); |
4547 | chan->num_conf_req++; | 4565 | chan->num_conf_req++; |
4548 | } | 4566 | } |
4549 | } else { | ||
4550 | /* Outgoing channel on AMP */ | ||
4551 | if (result == L2CAP_CR_SUCCESS) { | ||
4552 | chan->local_amp_id = local_amp_id; | ||
4553 | l2cap_send_create_chan_req(chan, remote_amp_id); | ||
4554 | } else { | ||
4555 | /* Revert to BR/EDR connect */ | ||
4556 | l2cap_send_conn_req(chan); | ||
4557 | } | ||
4558 | } | 4567 | } |
4559 | } | 4568 | } |
4560 | 4569 | ||
@@ -4612,7 +4621,8 @@ static void l2cap_do_move_cancel(struct l2cap_chan *chan, int result) | |||
4612 | l2cap_ertm_send(chan); | 4621 | l2cap_ertm_send(chan); |
4613 | } | 4622 | } |
4614 | 4623 | ||
4615 | void l2cap_physical_cfm(struct l2cap_chan *chan, int result) | 4624 | /* Invoke with locked chan */ |
4625 | void __l2cap_physical_cfm(struct l2cap_chan *chan, int result) | ||
4616 | { | 4626 | { |
4617 | u8 local_amp_id = chan->local_amp_id; | 4627 | u8 local_amp_id = chan->local_amp_id; |
4618 | u8 remote_amp_id = chan->remote_amp_id; | 4628 | u8 remote_amp_id = chan->remote_amp_id; |
@@ -4620,8 +4630,6 @@ void l2cap_physical_cfm(struct l2cap_chan *chan, int result) | |||
4620 | BT_DBG("chan %p, result %d, local_amp_id %d, remote_amp_id %d", | 4630 | BT_DBG("chan %p, result %d, local_amp_id %d, remote_amp_id %d", |
4621 | chan, result, local_amp_id, remote_amp_id); | 4631 | chan, result, local_amp_id, remote_amp_id); |
4622 | 4632 | ||
4623 | l2cap_chan_lock(chan); | ||
4624 | |||
4625 | if (chan->state == BT_DISCONN || chan->state == BT_CLOSED) { | 4633 | if (chan->state == BT_DISCONN || chan->state == BT_CLOSED) { |
4626 | l2cap_chan_unlock(chan); | 4634 | l2cap_chan_unlock(chan); |
4627 | return; | 4635 | return; |
@@ -4645,8 +4653,6 @@ void l2cap_physical_cfm(struct l2cap_chan *chan, int result) | |||
4645 | break; | 4653 | break; |
4646 | } | 4654 | } |
4647 | } | 4655 | } |
4648 | |||
4649 | l2cap_chan_unlock(chan); | ||
4650 | } | 4656 | } |
4651 | 4657 | ||
4652 | static inline int l2cap_move_channel_req(struct l2cap_conn *conn, | 4658 | static inline int l2cap_move_channel_req(struct l2cap_conn *conn, |
@@ -6086,7 +6092,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) | |||
6086 | control->super); | 6092 | control->super); |
6087 | 6093 | ||
6088 | if (len != 0) { | 6094 | if (len != 0) { |
6089 | BT_ERR("%d", len); | 6095 | BT_ERR("Trailing bytes: %d in sframe", len); |
6090 | l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); | 6096 | l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); |
6091 | goto drop; | 6097 | goto drop; |
6092 | } | 6098 | } |
@@ -6380,7 +6386,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) | |||
6380 | continue; | 6386 | continue; |
6381 | } | 6387 | } |
6382 | 6388 | ||
6383 | if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) { | 6389 | if (!__l2cap_no_conn_pending(chan)) { |
6384 | l2cap_chan_unlock(chan); | 6390 | l2cap_chan_unlock(chan); |
6385 | continue; | 6391 | continue; |
6386 | } | 6392 | } |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a97948b96b49..142764aec2af 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -485,7 +485,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data) | |||
485 | ptr += (name_len + 2); | 485 | ptr += (name_len + 2); |
486 | } | 486 | } |
487 | 487 | ||
488 | if (hdev->inq_tx_power) { | 488 | if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) { |
489 | ptr[0] = 2; | 489 | ptr[0] = 2; |
490 | ptr[1] = EIR_TX_POWER; | 490 | ptr[1] = EIR_TX_POWER; |
491 | ptr[2] = (u8) hdev->inq_tx_power; | 491 | ptr[2] = (u8) hdev->inq_tx_power; |