aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)