@@ -2203,7 +2203,8 @@ static int set_mesh(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
22032203
22042204 bt_dev_dbg (hdev , "sock %p" , sk );
22052205
2206- if (!lmp_le_capable (hdev ))
2206+ if (!lmp_le_capable (hdev ) ||
2207+ !hci_dev_test_flag (hdev , HCI_MESH_EXPERIMENTAL ))
22072208 return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_SET_MESH_RECEIVER ,
22082209 MGMT_STATUS_NOT_SUPPORTED );
22092210
@@ -2322,7 +2323,8 @@ static int mesh_features(struct sock *sk, struct hci_dev *hdev,
23222323{
23232324 struct mgmt_rp_mesh_read_features rp ;
23242325
2325- if (!lmp_le_capable (hdev ))
2326+ if (!lmp_le_capable (hdev ) ||
2327+ !hci_dev_test_flag (hdev , HCI_MESH_EXPERIMENTAL ))
23262328 return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_MESH_READ_FEATURES ,
23272329 MGMT_STATUS_NOT_SUPPORTED );
23282330
@@ -2376,6 +2378,11 @@ static int mesh_send_cancel(struct sock *sk, struct hci_dev *hdev,
23762378 struct mgmt_pending_cmd * cmd ;
23772379 int err ;
23782380
2381+ if (!lmp_le_capable (hdev ) ||
2382+ !hci_dev_test_flag (hdev , HCI_MESH_EXPERIMENTAL ))
2383+ return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_MESH_SEND_CANCEL ,
2384+ MGMT_STATUS_NOT_SUPPORTED );
2385+
23792386 if (!hci_dev_test_flag (hdev , HCI_LE_ENABLED ))
23802387 return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_MESH_SEND_CANCEL ,
23812388 MGMT_STATUS_REJECTED );
@@ -2407,6 +2414,10 @@ static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
24072414 bool sending ;
24082415 int err = 0 ;
24092416
2417+ if (!lmp_le_capable (hdev ) ||
2418+ !hci_dev_test_flag (hdev , HCI_MESH_EXPERIMENTAL ))
2419+ return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_MESH_SEND ,
2420+ MGMT_STATUS_NOT_SUPPORTED );
24102421 if (!hci_dev_test_flag (hdev , HCI_LE_ENABLED ) ||
24112422 len <= MGMT_MESH_SEND_SIZE ||
24122423 len > (MGMT_MESH_SEND_SIZE + 31 ))
@@ -4365,17 +4376,30 @@ static const u8 iso_socket_uuid[16] = {
43654376 0x6a , 0x49 , 0xe0 , 0x05 , 0x88 , 0xf1 , 0xba , 0x6f ,
43664377};
43674378
4379+ /* 2ce463d7-7a03-4d8d-bf05-5f24e8f36e76 */
4380+ static const u8 mgmt_mesh_uuid [16 ] = {
4381+ 0x76 , 0x6e , 0xf3 , 0xe8 , 0x24 , 0x5f , 0x05 , 0xbf ,
4382+ 0x8d , 0x4d , 0x03 , 0x7a , 0xd7 , 0x63 , 0xe4 , 0x2c ,
4383+ };
4384+
43684385static int read_exp_features_info (struct sock * sk , struct hci_dev * hdev ,
43694386 void * data , u16 data_len )
43704387{
4371- char buf [ 122 ]; /* Enough space for 6 features: 2 + 20 * 6 */
4372- struct mgmt_rp_read_exp_features_info * rp = ( void * ) buf ;
4388+ struct mgmt_rp_read_exp_features_info * rp ;
4389+ size_t len ;
43734390 u16 idx = 0 ;
43744391 u32 flags ;
4392+ int status ;
43754393
43764394 bt_dev_dbg (hdev , "sock %p" , sk );
43774395
4378- memset (& buf , 0 , sizeof (buf ));
4396+ /* Enough space for 7 features */
4397+ len = sizeof (* rp ) + (sizeof (rp -> features [0 ]) * 7 );
4398+ rp = kmalloc (len , GFP_KERNEL );
4399+ if (!rp )
4400+ return - ENOMEM ;
4401+
4402+ memset (rp , 0 , len );
43794403
43804404#ifdef CONFIG_BT_FEATURE_DEBUG
43814405 if (!hdev ) {
@@ -4439,16 +4463,30 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
44394463 idx ++ ;
44404464 }
44414465
4466+ if (hdev && lmp_le_capable (hdev )) {
4467+ if (hci_dev_test_flag (hdev , HCI_MESH_EXPERIMENTAL ))
4468+ flags = BIT (0 );
4469+ else
4470+ flags = 0 ;
4471+
4472+ memcpy (rp -> features [idx ].uuid , mgmt_mesh_uuid , 16 );
4473+ rp -> features [idx ].flags = cpu_to_le32 (flags );
4474+ idx ++ ;
4475+ }
4476+
44424477 rp -> feature_count = cpu_to_le16 (idx );
44434478
44444479 /* After reading the experimental features information, enable
44454480 * the events to update client on any future change.
44464481 */
44474482 hci_sock_set_flag (sk , HCI_MGMT_EXP_FEATURE_EVENTS );
44484483
4449- return mgmt_cmd_complete (sk , hdev ? hdev -> id : MGMT_INDEX_NONE ,
4450- MGMT_OP_READ_EXP_FEATURES_INFO ,
4451- 0 , rp , sizeof (* rp ) + (20 * idx ));
4484+ status = mgmt_cmd_complete (sk , hdev ? hdev -> id : MGMT_INDEX_NONE ,
4485+ MGMT_OP_READ_EXP_FEATURES_INFO ,
4486+ 0 , rp , sizeof (* rp ) + (20 * idx ));
4487+
4488+ kfree (rp );
4489+ return status ;
44524490}
44534491
44544492static int exp_ll_privacy_feature_changed (bool enabled , struct hci_dev * hdev ,
@@ -4576,6 +4614,63 @@ static int set_debug_func(struct sock *sk, struct hci_dev *hdev,
45764614}
45774615#endif
45784616
4617+ static int set_mgmt_mesh_func (struct sock * sk , struct hci_dev * hdev ,
4618+ struct mgmt_cp_set_exp_feature * cp , u16 data_len )
4619+ {
4620+ struct mgmt_rp_set_exp_feature rp ;
4621+ bool val , changed ;
4622+ int err ;
4623+
4624+ /* Command requires to use the controller index */
4625+ if (!hdev )
4626+ return mgmt_cmd_status (sk , MGMT_INDEX_NONE ,
4627+ MGMT_OP_SET_EXP_FEATURE ,
4628+ MGMT_STATUS_INVALID_INDEX );
4629+
4630+ /* Changes can only be made when controller is powered down */
4631+ if (hdev_is_powered (hdev ))
4632+ return mgmt_cmd_status (sk , hdev -> id ,
4633+ MGMT_OP_SET_EXP_FEATURE ,
4634+ MGMT_STATUS_REJECTED );
4635+
4636+ /* Parameters are limited to a single octet */
4637+ if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1 )
4638+ return mgmt_cmd_status (sk , hdev -> id ,
4639+ MGMT_OP_SET_EXP_FEATURE ,
4640+ MGMT_STATUS_INVALID_PARAMS );
4641+
4642+ /* Only boolean on/off is supported */
4643+ if (cp -> param [0 ] != 0x00 && cp -> param [0 ] != 0x01 )
4644+ return mgmt_cmd_status (sk , hdev -> id ,
4645+ MGMT_OP_SET_EXP_FEATURE ,
4646+ MGMT_STATUS_INVALID_PARAMS );
4647+
4648+ val = !!cp -> param [0 ];
4649+
4650+ if (val ) {
4651+ changed = !hci_dev_test_and_set_flag (hdev ,
4652+ HCI_MESH_EXPERIMENTAL );
4653+ } else {
4654+ hci_dev_clear_flag (hdev , HCI_MESH );
4655+ changed = hci_dev_test_and_clear_flag (hdev ,
4656+ HCI_MESH_EXPERIMENTAL );
4657+ }
4658+
4659+ memcpy (rp .uuid , mgmt_mesh_uuid , 16 );
4660+ rp .flags = cpu_to_le32 (val ? BIT (0 ) : 0 );
4661+
4662+ hci_sock_set_flag (sk , HCI_MGMT_EXP_FEATURE_EVENTS );
4663+
4664+ err = mgmt_cmd_complete (sk , hdev -> id ,
4665+ MGMT_OP_SET_EXP_FEATURE , 0 ,
4666+ & rp , sizeof (rp ));
4667+
4668+ if (changed )
4669+ exp_feature_changed (hdev , mgmt_mesh_uuid , val , sk );
4670+
4671+ return err ;
4672+ }
4673+
45794674static int set_rpa_resolution_func (struct sock * sk , struct hci_dev * hdev ,
45804675 struct mgmt_cp_set_exp_feature * cp ,
45814676 u16 data_len )
@@ -4891,6 +4986,7 @@ static const struct mgmt_exp_feature {
48914986#ifdef CONFIG_BT_FEATURE_DEBUG
48924987 EXP_FEAT (debug_uuid , set_debug_func ),
48934988#endif
4989+ EXP_FEAT (mgmt_mesh_uuid , set_mgmt_mesh_func ),
48944990 EXP_FEAT (rpa_resolution_uuid , set_rpa_resolution_func ),
48954991 EXP_FEAT (quality_report_uuid , set_quality_report_func ),
48964992 EXP_FEAT (offload_codecs_uuid , set_offload_codec_func ),
0 commit comments