aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaganath Kanakkassery <jaganath.k.os@gmail.com>2018-07-19 07:39:35 -0400
committerMarcel Holtmann <marcel@holtmann.org>2018-07-30 07:44:52 -0400
commit0314f2867fa0c46d0fc1c23c80e7fab9435079df (patch)
tree0223f6b657a2b031cc7a64c29c7ed1badae92273
parent6244691fec4dd0adebca255e60e0ed7ac8155b2e (diff)
Bluetooth: Implement Set PHY Confguration command
This enables user to set phys which will be used in all subsequent connections. Also host will use the same in LE scanning as well. @ MGMT Command: Set PHY Configuration (0x0045) plen 4 Selected PHYs: 0x7fff BR 1M 1SLOT BR 1M 3SLOT BR 1M 5SLOT EDR 2M 1SLOT EDR 2M 3SLOT EDR 2M 5SLOT EDR 3M 1SLOT EDR 3M 3SLOT EDR 3M 5SLOT LE 1M TX LE 1M RX LE 2M TX LE 2M RX LE CODED TX LE CODED RX < HCI Command: LE Set Default PHY (0x08|0x0031) plen 3 All PHYs preference: 0x00 TX PHYs preference: 0x07 LE 1M LE 2M LE Coded RX PHYs preference: 0x07 LE 1M LE 2M LE Coded > HCI Event: Command Complete (0x0e) plen 4 LE Set Default PHY (0x08|0x0031) ncmd 1 Status: Success (0x00) @ MGMT Event: Command Complete (0x0001) plen 3 Set PHY Configuration (0x0045) plen 0 Status: Success (0x00) @ MGMT Event: PHY Configuration Changed (0x0026) plen 4 Selected PHYs: 0x7fff BR 1M 1SLOT BR 1M 3SLOT BR 1M 5SLOT EDR 2M 1SLOT EDR 2M 3SLOT EDR 2M 5SLOT EDR 3M 1SLOT EDR 3M 3SLOT EDR 3M 5SLOT LE 1M TX LE 1M RX LE 2M TX LE 2M RX LE CODED TX LE CODED RX Signed-off-by: Jaganath Kanakkassery <jaganathx.kanakkassery@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--include/net/bluetooth/mgmt.h19
-rw-r--r--net/bluetooth/hci_event.c26
-rw-r--r--net/bluetooth/mgmt.c182
3 files changed, 227 insertions, 0 deletions
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 1c93d6e83a6c..0916e203e5d9 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -629,6 +629,25 @@ struct mgmt_rp_get_phy_confguration {
629#define MGMT_PHY_LE_CODED_TX 0x00002000 629#define MGMT_PHY_LE_CODED_TX 0x00002000
630#define MGMT_PHY_LE_CODED_RX 0x00004000 630#define MGMT_PHY_LE_CODED_RX 0x00004000
631 631
632#define MGMT_PHY_BREDR_MASK (MGMT_PHY_BR_1M_1SLOT | MGMT_PHY_BR_1M_3SLOT | \
633 MGMT_PHY_BR_1M_5SLOT | MGMT_PHY_EDR_2M_1SLOT | \
634 MGMT_PHY_EDR_2M_3SLOT | MGMT_PHY_EDR_2M_5SLOT | \
635 MGMT_PHY_EDR_3M_1SLOT | MGMT_PHY_EDR_3M_3SLOT | \
636 MGMT_PHY_EDR_3M_5SLOT)
637#define MGMT_PHY_LE_MASK (MGMT_PHY_LE_1M_TX | MGMT_PHY_LE_1M_RX | \
638 MGMT_PHY_LE_2M_TX | MGMT_PHY_LE_2M_RX | \
639 MGMT_PHY_LE_CODED_TX | MGMT_PHY_LE_CODED_RX)
640#define MGMT_PHY_LE_TX_MASK (MGMT_PHY_LE_1M_TX | MGMT_PHY_LE_2M_TX | \
641 MGMT_PHY_LE_CODED_TX)
642#define MGMT_PHY_LE_RX_MASK (MGMT_PHY_LE_1M_RX | MGMT_PHY_LE_2M_RX | \
643 MGMT_PHY_LE_CODED_RX)
644
645#define MGMT_OP_SET_PHY_CONFIGURATION 0x0045
646struct mgmt_cp_set_phy_confguration {
647 __le32 selected_phys;
648} __packed;
649#define MGMT_SET_PHY_CONFIGURATION_SIZE 4
650
632#define MGMT_EV_CMD_COMPLETE 0x0001 651#define MGMT_EV_CMD_COMPLETE 0x0001
633struct mgmt_ev_cmd_complete { 652struct mgmt_ev_cmd_complete {
634 __le16 opcode; 653 __le16 opcode;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 68192152c23b..694231541a4c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1042,6 +1042,28 @@ static void hci_cc_le_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb)
1042 hci_dev_unlock(hdev); 1042 hci_dev_unlock(hdev);
1043} 1043}
1044 1044
1045static void hci_cc_le_set_default_phy(struct hci_dev *hdev, struct sk_buff *skb)
1046{
1047 __u8 status = *((__u8 *) skb->data);
1048 struct hci_cp_le_set_default_phy *cp;
1049
1050 BT_DBG("%s status 0x%2.2x", hdev->name, status);
1051
1052 if (status)
1053 return;
1054
1055 cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_DEFAULT_PHY);
1056 if (!cp)
1057 return;
1058
1059 hci_dev_lock(hdev);
1060
1061 hdev->le_tx_def_phys = cp->tx_phys;
1062 hdev->le_rx_def_phys = cp->rx_phys;
1063
1064 hci_dev_unlock(hdev);
1065}
1066
1045static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) 1067static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
1046{ 1068{
1047 __u8 *sent, status = *((__u8 *) skb->data); 1069 __u8 *sent, status = *((__u8 *) skb->data);
@@ -3163,6 +3185,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
3163 hci_cc_le_set_ext_scan_enable(hdev, skb); 3185 hci_cc_le_set_ext_scan_enable(hdev, skb);
3164 break; 3186 break;
3165 3187
3188 case HCI_OP_LE_SET_DEFAULT_PHY:
3189 hci_cc_le_set_default_phy(hdev, skb);
3190 break;
3191
3166 default: 3192 default:
3167 BT_DBG("%s opcode 0x%4.4x", hdev->name, *opcode); 3193 BT_DBG("%s opcode 0x%4.4x", hdev->name, *opcode);
3168 break; 3194 break;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index c8c3b39fa9f2..7cd6a37a63ee 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -3328,6 +3328,187 @@ static int get_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3328 &rp, sizeof(rp)); 3328 &rp, sizeof(rp));
3329} 3329}
3330 3330
3331static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
3332 u16 opcode, struct sk_buff *skb)
3333{
3334 struct mgmt_cp_set_phy_confguration *cp;
3335 struct mgmt_pending_cmd *cmd;
3336
3337 BT_DBG("status 0x%02x", status);
3338
3339 hci_dev_lock(hdev);
3340
3341 cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
3342 if (!cmd)
3343 goto unlock;
3344
3345 cp = cmd->param;
3346
3347 if (status) {
3348 mgmt_cmd_status(cmd->sk, hdev->id,
3349 MGMT_OP_SET_PHY_CONFIGURATION,
3350 mgmt_status(status));
3351 } else {
3352 mgmt_cmd_complete(cmd->sk, hdev->id,
3353 MGMT_OP_SET_PHY_CONFIGURATION, 0,
3354 NULL, 0);
3355 }
3356
3357 mgmt_pending_remove(cmd);
3358
3359unlock:
3360 hci_dev_unlock(hdev);
3361}
3362
3363static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
3364 void *data, u16 len)
3365{
3366 struct mgmt_cp_set_phy_confguration *cp = data;
3367 struct hci_cp_le_set_default_phy cp_phy;
3368 struct mgmt_pending_cmd *cmd;
3369 struct hci_request req;
3370 u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
3371 u16 pkt_type = (HCI_DH1 | HCI_DM1);
3372 int err;
3373
3374 BT_DBG("sock %p %s", sk, hdev->name);
3375
3376 configurable_phys = get_configurable_phys(hdev);
3377 supported_phys = get_supported_phys(hdev);
3378 selected_phys = __le32_to_cpu(cp->selected_phys);
3379
3380 if (selected_phys & ~supported_phys)
3381 return mgmt_cmd_status(sk, hdev->id,
3382 MGMT_OP_SET_PHY_CONFIGURATION,
3383 MGMT_STATUS_INVALID_PARAMS);
3384
3385 unconfigure_phys = supported_phys & ~configurable_phys;
3386
3387 if ((selected_phys & unconfigure_phys) != unconfigure_phys)
3388 return mgmt_cmd_status(sk, hdev->id,
3389 MGMT_OP_SET_PHY_CONFIGURATION,
3390 MGMT_STATUS_INVALID_PARAMS);
3391
3392 if (selected_phys == get_selected_phys(hdev))
3393 return mgmt_cmd_complete(sk, hdev->id,
3394 MGMT_OP_SET_PHY_CONFIGURATION,
3395 0, NULL, 0);
3396
3397 hci_dev_lock(hdev);
3398
3399 if (!hdev_is_powered(hdev)) {
3400 err = mgmt_cmd_status(sk, hdev->id,
3401 MGMT_OP_SET_PHY_CONFIGURATION,
3402 MGMT_STATUS_REJECTED);
3403 goto unlock;
3404 }
3405
3406 if (pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev)) {
3407 err = mgmt_cmd_status(sk, hdev->id,
3408 MGMT_OP_SET_PHY_CONFIGURATION,
3409 MGMT_STATUS_BUSY);
3410 goto unlock;
3411 }
3412
3413 if (selected_phys & MGMT_PHY_BR_1M_3SLOT)
3414 pkt_type |= (HCI_DH3 | HCI_DM3);
3415 else
3416 pkt_type &= ~(HCI_DH3 | HCI_DM3);
3417
3418 if (selected_phys & MGMT_PHY_BR_1M_5SLOT)
3419 pkt_type |= (HCI_DH5 | HCI_DM5);
3420 else
3421 pkt_type &= ~(HCI_DH5 | HCI_DM5);
3422
3423 if (selected_phys & MGMT_PHY_EDR_2M_1SLOT)
3424 pkt_type &= ~HCI_2DH1;
3425 else
3426 pkt_type |= HCI_2DH1;
3427
3428 if (selected_phys & MGMT_PHY_EDR_2M_3SLOT)
3429 pkt_type &= ~HCI_2DH3;
3430 else
3431 pkt_type |= HCI_2DH3;
3432
3433 if (selected_phys & MGMT_PHY_EDR_2M_5SLOT)
3434 pkt_type &= ~HCI_2DH5;
3435 else
3436 pkt_type |= HCI_2DH5;
3437
3438 if (selected_phys & MGMT_PHY_EDR_3M_1SLOT)
3439 pkt_type &= ~HCI_3DH1;
3440 else
3441 pkt_type |= HCI_3DH1;
3442
3443 if (selected_phys & MGMT_PHY_EDR_3M_3SLOT)
3444 pkt_type &= ~HCI_3DH3;
3445 else
3446 pkt_type |= HCI_3DH3;
3447
3448 if (selected_phys & MGMT_PHY_EDR_3M_5SLOT)
3449 pkt_type &= ~HCI_3DH5;
3450 else
3451 pkt_type |= HCI_3DH5;
3452
3453 if (pkt_type != hdev->pkt_type)
3454 hdev->pkt_type = pkt_type;
3455
3456 if ((selected_phys & MGMT_PHY_LE_MASK) ==
3457 (get_selected_phys(hdev) & MGMT_PHY_LE_MASK)) {
3458 err = mgmt_cmd_complete(sk, hdev->id,
3459 MGMT_OP_SET_PHY_CONFIGURATION,
3460 0, NULL, 0);
3461
3462 goto unlock;
3463 }
3464
3465 cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
3466 len);
3467 if (!cmd) {
3468 err = -ENOMEM;
3469 goto unlock;
3470 }
3471
3472 hci_req_init(&req, hdev);
3473
3474 memset(&cp_phy, 0, sizeof(cp_phy));
3475
3476 if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
3477 cp_phy.all_phys |= 0x01;
3478
3479 if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
3480 cp_phy.all_phys |= 0x02;
3481
3482 if (selected_phys & MGMT_PHY_LE_1M_TX)
3483 cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
3484
3485 if (selected_phys & MGMT_PHY_LE_2M_TX)
3486 cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
3487
3488 if (selected_phys & MGMT_PHY_LE_CODED_TX)
3489 cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
3490
3491 if (selected_phys & MGMT_PHY_LE_1M_RX)
3492 cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
3493
3494 if (selected_phys & MGMT_PHY_LE_2M_RX)
3495 cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
3496
3497 if (selected_phys & MGMT_PHY_LE_CODED_RX)
3498 cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
3499
3500 hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
3501
3502 err = hci_req_run_skb(&req, set_default_phy_complete);
3503 if (err < 0)
3504 mgmt_pending_remove(cmd);
3505
3506unlock:
3507 hci_dev_unlock(hdev);
3508
3509 return err;
3510}
3511
3331static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status, 3512static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
3332 u16 opcode, struct sk_buff *skb) 3513 u16 opcode, struct sk_buff *skb)
3333{ 3514{
@@ -6689,6 +6870,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
6689 HCI_MGMT_UNTRUSTED }, 6870 HCI_MGMT_UNTRUSTED },
6690 { set_appearance, MGMT_SET_APPEARANCE_SIZE }, 6871 { set_appearance, MGMT_SET_APPEARANCE_SIZE },
6691 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE }, 6872 { get_phy_configuration, MGMT_GET_PHY_CONFIGURATION_SIZE },
6873 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE },
6692}; 6874};
6693 6875
6694void mgmt_index_added(struct hci_dev *hdev) 6876void mgmt_index_added(struct hci_dev *hdev)