@@ -795,10 +795,15 @@ static u32 get_supported_settings(struct hci_dev *hdev)
795795
796796 if (lmp_le_capable (hdev )) {
797797 settings |= MGMT_SETTING_LE ;
798- settings |= MGMT_SETTING_ADVERTISING ;
799798 settings |= MGMT_SETTING_SECURE_CONN ;
800799 settings |= MGMT_SETTING_PRIVACY ;
801800 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 ;
802807 }
803808
804809 if (test_bit (HCI_QUIRK_EXTERNAL_CONFIG , & hdev -> quirks ) ||
@@ -3759,10 +3764,16 @@ static const u8 simult_central_periph_uuid[16] = {
37593764 0x96 , 0x46 , 0xc0 , 0x42 , 0xb5 , 0x10 , 0x1b , 0x67 ,
37603765};
37613766
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+
37623773static int read_exp_features_info (struct sock * sk , struct hci_dev * hdev ,
37633774 void * data , u16 data_len )
37643775{
3765- char buf [44 ];
3776+ char buf [62 ]; /* Enough space for 3 features */
37663777 struct mgmt_rp_read_exp_features_info * rp = (void * )buf ;
37673778 u16 idx = 0 ;
37683779 u32 flags ;
@@ -3795,6 +3806,17 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
37953806 idx ++ ;
37963807 }
37973808
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+
37983820 rp -> feature_count = cpu_to_le16 (idx );
37993821
38003822 /* After reading the experimental features information, enable
@@ -3807,6 +3829,21 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
38073829 0 , rp , sizeof (* rp ) + (20 * idx ));
38083830}
38093831
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+
38103847#ifdef CONFIG_BT_FEATURE_DEBUG
38113848static int exp_debug_feature_changed (bool enabled , struct sock * skip )
38123849{
@@ -3845,6 +3882,16 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
38453882 }
38463883#endif
38473884
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+
38483895 hci_sock_set_flag (sk , HCI_MGMT_EXP_FEATURE_EVENTS );
38493896
38503897 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,
38953942 }
38963943#endif
38973944
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+
38984008 return mgmt_cmd_status (sk , hdev ? hdev -> id : MGMT_INDEX_NONE ,
38994009 MGMT_OP_SET_EXP_FEATURE ,
39004010 MGMT_STATUS_NOT_SUPPORTED );
@@ -5040,6 +5150,13 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
50405150 return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_SET_ADVERTISING ,
50415151 status );
50425152
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+
50435160 if (cp -> val != 0x00 && cp -> val != 0x01 && cp -> val != 0x02 )
50445161 return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_SET_ADVERTISING ,
50455162 MGMT_STATUS_INVALID_PARAMS );
@@ -7112,6 +7229,13 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
71127229 return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_READ_ADV_FEATURES ,
71137230 MGMT_STATUS_REJECTED );
71147231
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+
71157239 hci_dev_lock (hdev );
71167240
71177241 rp_len = sizeof (* rp ) + hdev -> adv_instance_cnt ;
@@ -7315,6 +7439,13 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
73157439 return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_ADD_ADVERTISING ,
73167440 status );
73177441
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+
73187449 if (cp -> instance < 1 || cp -> instance > HCI_MAX_ADV_INSTANCES )
73197450 return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_ADD_ADVERTISING ,
73207451 MGMT_STATUS_INVALID_PARAMS );
@@ -7479,6 +7610,13 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
74797610
74807611 bt_dev_dbg (hdev , "sock %p" , sk );
74817612
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+
74827620 hci_dev_lock (hdev );
74837621
74847622 if (cp -> instance && !hci_find_adv_instance (hdev , cp -> instance )) {
0 commit comments