@@ -2203,7 +2203,8 @@ static int set_mesh(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
2203
2203
2204
2204
bt_dev_dbg (hdev , "sock %p" , sk );
2205
2205
2206
- if (!lmp_le_capable (hdev ))
2206
+ if (!lmp_le_capable (hdev ) ||
2207
+ !hci_dev_test_flag (hdev , HCI_MESH_EXPERIMENTAL ))
2207
2208
return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_SET_MESH_RECEIVER ,
2208
2209
MGMT_STATUS_NOT_SUPPORTED );
2209
2210
@@ -2322,7 +2323,8 @@ static int mesh_features(struct sock *sk, struct hci_dev *hdev,
2322
2323
{
2323
2324
struct mgmt_rp_mesh_read_features rp ;
2324
2325
2325
- if (!lmp_le_capable (hdev ))
2326
+ if (!lmp_le_capable (hdev ) ||
2327
+ !hci_dev_test_flag (hdev , HCI_MESH_EXPERIMENTAL ))
2326
2328
return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_MESH_READ_FEATURES ,
2327
2329
MGMT_STATUS_NOT_SUPPORTED );
2328
2330
@@ -2376,6 +2378,11 @@ static int mesh_send_cancel(struct sock *sk, struct hci_dev *hdev,
2376
2378
struct mgmt_pending_cmd * cmd ;
2377
2379
int err ;
2378
2380
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
+
2379
2386
if (!hci_dev_test_flag (hdev , HCI_LE_ENABLED ))
2380
2387
return mgmt_cmd_status (sk , hdev -> id , MGMT_OP_MESH_SEND_CANCEL ,
2381
2388
MGMT_STATUS_REJECTED );
@@ -2407,6 +2414,10 @@ static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
2407
2414
bool sending ;
2408
2415
int err = 0 ;
2409
2416
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 );
2410
2421
if (!hci_dev_test_flag (hdev , HCI_LE_ENABLED ) ||
2411
2422
len <= MGMT_MESH_SEND_SIZE ||
2412
2423
len > (MGMT_MESH_SEND_SIZE + 31 ))
@@ -4365,17 +4376,30 @@ static const u8 iso_socket_uuid[16] = {
4365
4376
0x6a , 0x49 , 0xe0 , 0x05 , 0x88 , 0xf1 , 0xba , 0x6f ,
4366
4377
};
4367
4378
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
+
4368
4385
static int read_exp_features_info (struct sock * sk , struct hci_dev * hdev ,
4369
4386
void * data , u16 data_len )
4370
4387
{
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 ;
4373
4390
u16 idx = 0 ;
4374
4391
u32 flags ;
4392
+ int status ;
4375
4393
4376
4394
bt_dev_dbg (hdev , "sock %p" , sk );
4377
4395
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 );
4379
4403
4380
4404
#ifdef CONFIG_BT_FEATURE_DEBUG
4381
4405
if (!hdev ) {
@@ -4439,16 +4463,30 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
4439
4463
idx ++ ;
4440
4464
}
4441
4465
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
+
4442
4477
rp -> feature_count = cpu_to_le16 (idx );
4443
4478
4444
4479
/* After reading the experimental features information, enable
4445
4480
* the events to update client on any future change.
4446
4481
*/
4447
4482
hci_sock_set_flag (sk , HCI_MGMT_EXP_FEATURE_EVENTS );
4448
4483
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 ;
4452
4490
}
4453
4491
4454
4492
static 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,
4576
4614
}
4577
4615
#endif
4578
4616
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
+
4579
4674
static int set_rpa_resolution_func (struct sock * sk , struct hci_dev * hdev ,
4580
4675
struct mgmt_cp_set_exp_feature * cp ,
4581
4676
u16 data_len )
@@ -4891,6 +4986,7 @@ static const struct mgmt_exp_feature {
4891
4986
#ifdef CONFIG_BT_FEATURE_DEBUG
4892
4987
EXP_FEAT (debug_uuid , set_debug_func ),
4893
4988
#endif
4989
+ EXP_FEAT (mgmt_mesh_uuid , set_mgmt_mesh_func ),
4894
4990
EXP_FEAT (rpa_resolution_uuid , set_rpa_resolution_func ),
4895
4991
EXP_FEAT (quality_report_uuid , set_quality_report_func ),
4896
4992
EXP_FEAT (offload_codecs_uuid , set_offload_codec_func ),
0 commit comments