@@ -795,10 +795,15 @@ static u32 get_supported_settings(struct hci_dev *hdev)
795
795
796
796
if (lmp_le_capable (hdev )) {
797
797
settings |= MGMT_SETTING_LE ;
798
- settings |= MGMT_SETTING_ADVERTISING ;
799
798
settings |= MGMT_SETTING_SECURE_CONN ;
800
799
settings |= MGMT_SETTING_PRIVACY ;
801
800
settings |= MGMT_SETTING_STATIC_ADDRESS ;
801
+
802
+ /* When the experimental feature for LL Privacy support is
803
+ * enabled, then advertising is no longer supported.
804
+ */
805
+ if (!hci_dev_test_flag (hdev , HCI_ENABLE_LL_PRIVACY ))
806
+ settings |= MGMT_SETTING_ADVERTISING ;
802
807
}
803
808
804
809
if (test_bit (HCI_QUIRK_EXTERNAL_CONFIG , & hdev -> quirks ) ||
@@ -3759,10 +3764,16 @@ static const u8 simult_central_periph_uuid[16] = {
3759
3764
0x96 , 0x46 , 0xc0 , 0x42 , 0xb5 , 0x10 , 0x1b , 0x67 ,
3760
3765
};
3761
3766
3767
+ /* 15c0a148-c273-11ea-b3de-0242ac130004 */
3768
+ static const u8 rpa_resolution_uuid [16 ] = {
3769
+ 0x04 , 0x00 , 0x13 , 0xac , 0x42 , 0x02 , 0xde , 0xb3 ,
3770
+ 0xea , 0x11 , 0x73 , 0xc2 , 0x48 , 0xa1 , 0xc0 , 0x15 ,
3771
+ };
3772
+
3762
3773
static int read_exp_features_info (struct sock * sk , struct hci_dev * hdev ,
3763
3774
void * data , u16 data_len )
3764
3775
{
3765
- char buf [44 ];
3776
+ char buf [62 ]; /* Enough space for 3 features */
3766
3777
struct mgmt_rp_read_exp_features_info * rp = (void * )buf ;
3767
3778
u16 idx = 0 ;
3768
3779
u32 flags ;
@@ -3795,6 +3806,17 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
3795
3806
idx ++ ;
3796
3807
}
3797
3808
3809
+ if (hdev && use_ll_privacy (hdev )) {
3810
+ if (hci_dev_test_flag (hdev , HCI_ENABLE_LL_PRIVACY ))
3811
+ flags = BIT (0 ) | BIT (1 );
3812
+ else
3813
+ flags = BIT (1 );
3814
+
3815
+ memcpy (rp -> features [idx ].uuid , rpa_resolution_uuid , 16 );
3816
+ rp -> features [idx ].flags = cpu_to_le32 (flags );
3817
+ idx ++ ;
3818
+ }
3819
+
3798
3820
rp -> feature_count = cpu_to_le16 (idx );
3799
3821
3800
3822
/* After reading the experimental features information, enable
@@ -3807,6 +3829,21 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
3807
3829
0 , rp , sizeof (* rp ) + (20 * idx ));
3808
3830
}
3809
3831
3832
+ static int exp_ll_privacy_feature_changed (bool enabled , struct hci_dev * hdev ,
3833
+ struct sock * skip )
3834
+ {
3835
+ struct mgmt_ev_exp_feature_changed ev ;
3836
+
3837
+ memset (& ev , 0 , sizeof (ev ));
3838
+ memcpy (ev .uuid , rpa_resolution_uuid , 16 );
3839
+ ev .flags = cpu_to_le32 ((enabled ? BIT (0 ) : 0 ) | BIT (1 ));
3840
+
3841
+ return mgmt_limited_event (MGMT_EV_EXP_FEATURE_CHANGED , hdev ,
3842
+ & ev , sizeof (ev ),
3843
+ HCI_MGMT_EXP_FEATURE_EVENTS , skip );
3844
+
3845
+ }
3846
+
3810
3847
#ifdef CONFIG_BT_FEATURE_DEBUG
3811
3848
static int exp_debug_feature_changed (bool enabled , struct sock * skip )
3812
3849
{
@@ -3845,6 +3882,16 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
3845
3882
}
3846
3883
#endif
3847
3884
3885
+ if (hdev && use_ll_privacy (hdev ) && !hdev_is_powered (hdev )) {
3886
+ bool changed = hci_dev_test_flag (hdev ,
3887
+ HCI_ENABLE_LL_PRIVACY );
3888
+
3889
+ hci_dev_clear_flag (hdev , HCI_ENABLE_LL_PRIVACY );
3890
+
3891
+ if (changed )
3892
+ exp_ll_privacy_feature_changed (false, hdev , sk );
3893
+ }
3894
+
3848
3895
hci_sock_set_flag (sk , HCI_MGMT_EXP_FEATURE_EVENTS );
3849
3896
3850
3897
return mgmt_cmd_complete (sk , hdev ? hdev -> id : MGMT_INDEX_NONE ,
@@ -3895,6 +3942,69 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
3895
3942
}
3896
3943
#endif
3897
3944
3945
+ if (!memcmp (cp -> uuid , rpa_resolution_uuid , 16 )) {
3946
+ bool val , changed ;
3947
+ int err ;
3948
+ u32 flags ;
3949
+
3950
+ /* Command requires to use the controller index */
3951
+ if (!hdev )
3952
+ return mgmt_cmd_status (sk , MGMT_INDEX_NONE ,
3953
+ MGMT_OP_SET_EXP_FEATURE ,
3954
+ MGMT_STATUS_INVALID_INDEX );
3955
+
3956
+ /* Changes can only be made when controller is powered down */
3957
+ if (hdev_is_powered (hdev ))
3958
+ return mgmt_cmd_status (sk , hdev -> id ,
3959
+ MGMT_OP_SET_EXP_FEATURE ,
3960
+ MGMT_STATUS_NOT_POWERED );
3961
+
3962
+ /* Parameters are limited to a single octet */
3963
+ if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1 )
3964
+ return mgmt_cmd_status (sk , hdev -> id ,
3965
+ MGMT_OP_SET_EXP_FEATURE ,
3966
+ MGMT_STATUS_INVALID_PARAMS );
3967
+
3968
+ /* Only boolean on/off is supported */
3969
+ if (cp -> param [0 ] != 0x00 && cp -> param [0 ] != 0x01 )
3970
+ return mgmt_cmd_status (sk , hdev -> id ,
3971
+ MGMT_OP_SET_EXP_FEATURE ,
3972
+ MGMT_STATUS_INVALID_PARAMS );
3973
+
3974
+ val = !!cp -> param [0 ];
3975
+
3976
+ if (val ) {
3977
+ changed = !hci_dev_test_flag (hdev ,
3978
+ HCI_ENABLE_LL_PRIVACY );
3979
+ hci_dev_set_flag (hdev , HCI_ENABLE_LL_PRIVACY );
3980
+ hci_dev_clear_flag (hdev , HCI_ADVERTISING );
3981
+
3982
+ /* Enable LL privacy + supported settings changed */
3983
+ flags = BIT (0 ) | BIT (1 );
3984
+ } else {
3985
+ changed = hci_dev_test_flag (hdev ,
3986
+ HCI_ENABLE_LL_PRIVACY );
3987
+ hci_dev_clear_flag (hdev , HCI_ENABLE_LL_PRIVACY );
3988
+
3989
+ /* Disable LL privacy + supported settings changed */
3990
+ flags = BIT (1 );
3991
+ }
3992
+
3993
+ memcpy (rp .uuid , rpa_resolution_uuid , 16 );
3994
+ rp .flags = cpu_to_le32 (flags );
3995
+
3996
+ hci_sock_set_flag (sk , HCI_MGMT_EXP_FEATURE_EVENTS );
3997
+
3998
+ err = mgmt_cmd_complete (sk , hdev -> id ,
3999
+ MGMT_OP_SET_EXP_FEATURE , 0 ,
4000
+ & rp , sizeof (rp ));
4001
+
4002
+ if (changed )
4003
+ exp_ll_privacy_feature_changed (val , hdev , sk );
4004
+
4005
+ return err ;
4006
+ }
4007
+
3898
4008
return mgmt_cmd_status (sk , hdev ? hdev -> id : MGMT_INDEX_NONE ,
3899
4009
MGMT_OP_SET_EXP_FEATURE ,
3900
4010
MGMT_STATUS_NOT_SUPPORTED );
@@ -5040,6 +5150,13 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
5040
5150
return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_SET_ADVERTISING ,
5041
5151
status );
5042
5152
5153
+ /* Enabling the experimental LL Privay support disables support for
5154
+ * advertising.
5155
+ */
5156
+ if (hci_dev_test_flag (hdev , HCI_ENABLE_LL_PRIVACY ))
5157
+ return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_SET_ADVERTISING ,
5158
+ MGMT_STATUS_NOT_SUPPORTED );
5159
+
5043
5160
if (cp -> val != 0x00 && cp -> val != 0x01 && cp -> val != 0x02 )
5044
5161
return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_SET_ADVERTISING ,
5045
5162
MGMT_STATUS_INVALID_PARAMS );
@@ -7112,6 +7229,13 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
7112
7229
return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_READ_ADV_FEATURES ,
7113
7230
MGMT_STATUS_REJECTED );
7114
7231
7232
+ /* Enabling the experimental LL Privay support disables support for
7233
+ * advertising.
7234
+ */
7235
+ if (hci_dev_test_flag (hdev , HCI_ENABLE_LL_PRIVACY ))
7236
+ return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_SET_ADVERTISING ,
7237
+ MGMT_STATUS_NOT_SUPPORTED );
7238
+
7115
7239
hci_dev_lock (hdev );
7116
7240
7117
7241
rp_len = sizeof (* rp ) + hdev -> adv_instance_cnt ;
@@ -7315,6 +7439,13 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
7315
7439
return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_ADD_ADVERTISING ,
7316
7440
status );
7317
7441
7442
+ /* Enabling the experimental LL Privay support disables support for
7443
+ * advertising.
7444
+ */
7445
+ if (hci_dev_test_flag (hdev , HCI_ENABLE_LL_PRIVACY ))
7446
+ return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_SET_ADVERTISING ,
7447
+ MGMT_STATUS_NOT_SUPPORTED );
7448
+
7318
7449
if (cp -> instance < 1 || cp -> instance > HCI_MAX_ADV_INSTANCES )
7319
7450
return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_ADD_ADVERTISING ,
7320
7451
MGMT_STATUS_INVALID_PARAMS );
@@ -7479,6 +7610,13 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
7479
7610
7480
7611
bt_dev_dbg (hdev , "sock %p" , sk );
7481
7612
7613
+ /* Enabling the experimental LL Privay support disables support for
7614
+ * advertising.
7615
+ */
7616
+ if (hci_dev_test_flag (hdev , HCI_ENABLE_LL_PRIVACY ))
7617
+ return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_SET_ADVERTISING ,
7618
+ MGMT_STATUS_NOT_SUPPORTED );
7619
+
7482
7620
hci_dev_lock (hdev );
7483
7621
7484
7622
if (cp -> instance && !hci_find_adv_instance (hdev , cp -> instance )) {
0 commit comments