[PATCH] Bluetooth: Check inquiry status before sending one

2021-03-31 Thread Archie Pusaka
From: Archie Pusaka 

There is a possibility where HCI_INQUIRY flag is set but we still
send HCI_OP_INQUIRY anyway.

Such a case can be reproduced by connecting to an LE device while
active scanning. When the device is discovered, we initiate a
connection, stop LE Scan, and send Discovery MGMT with status
disabled, but we don't cancel the inquiry.

Signed-off-by: Archie Pusaka 
Reviewed-by: Sonny Sasaka 
---

 net/bluetooth/hci_request.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index 8ace5d34b01e..5a5ec7ed15ea 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -2952,6 +2952,9 @@ static int bredr_inquiry(struct hci_request *req, 
unsigned long opt)
const u8 liac[3] = { 0x00, 0x8b, 0x9e };
struct hci_cp_inquiry cp;
 
+   if (test_bit(HCI_INQUIRY, >hdev->flags))
+   return 0;
+
bt_dev_dbg(req->hdev, "");
 
hci_dev_lock(req->hdev);
-- 
2.31.0.291.g576ba9dcdaf-goog



Re: [PATCH] Bluetooth: check for zapped sk before connecting

2021-03-23 Thread Archie Pusaka
Hi Marcel,

Thanks for your suggestion. I implemented it in v2, please take another look.


On Mon, 22 Mar 2021 at 23:53, Marcel Holtmann  wrote:
>
> Hi Archie,
>
> > There is a possibility of receiving a zapped sock on
> > l2cap_sock_connect(). This could lead to interesting crashes, one
> > such case is tearing down an already tore l2cap_sock as is happened
> > with this call trace:
> >
> > __dump_stack lib/dump_stack.c:15 [inline]
> > dump_stack+0xc4/0x118 lib/dump_stack.c:56
> > register_lock_class kernel/locking/lockdep.c:792 [inline]
> > register_lock_class+0x239/0x6f6 kernel/locking/lockdep.c:742
> > __lock_acquire+0x209/0x1e27 kernel/locking/lockdep.c:3105
> > lock_acquire+0x29c/0x2fb kernel/locking/lockdep.c:3599
> > __raw_spin_lock_bh include/linux/spinlock_api_smp.h:137 [inline]
> > _raw_spin_lock_bh+0x38/0x47 kernel/locking/spinlock.c:175
> > spin_lock_bh include/linux/spinlock.h:307 [inline]
> > lock_sock_nested+0x44/0xfa net/core/sock.c:2518
> > l2cap_sock_teardown_cb+0x88/0x2fb net/bluetooth/l2cap_sock.c:1345
> > l2cap_chan_del+0xa3/0x383 net/bluetooth/l2cap_core.c:598
> > l2cap_chan_close+0x537/0x5dd net/bluetooth/l2cap_core.c:756
> > l2cap_chan_timeout+0x104/0x17e net/bluetooth/l2cap_core.c:429
> > process_one_work+0x7e3/0xcb0 kernel/workqueue.c:2064
> > worker_thread+0x5a5/0x773 kernel/workqueue.c:2196
> > kthread+0x291/0x2a6 kernel/kthread.c:211
> > ret_from_fork+0x4e/0x80 arch/x86/entry/entry_64.S:604
> >
> > Signed-off-by: Archie Pusaka 
> > Reported-by: syzbot+abfc0f5e668d4099a...@syzkaller.appspotmail.com
> > Reviewed-by: Alain Michaud 
> > Reviewed-by: Abhishek Pandit-Subedi 
> > Reviewed-by: Guenter Roeck 
> > ---
> >
> > net/bluetooth/l2cap_sock.c | 7 +++
> > 1 file changed, 7 insertions(+)
> >
> > diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
> > index f1b1edd0b697..b86fd8cc4dc1 100644
> > --- a/net/bluetooth/l2cap_sock.c
> > +++ b/net/bluetooth/l2cap_sock.c
> > @@ -182,6 +182,13 @@ static int l2cap_sock_connect(struct socket *sock, 
> > struct sockaddr *addr,
> >
> >   BT_DBG("sk %p", sk);
> >
> > + lock_sock(sk);
> > + if (sock_flag(sk, SOCK_ZAPPED)) {
> > + release_sock(sk);
> > + return -EINVAL;
> > + }
> > + release_sock(sk);
> > +
>
> hmmm. I wonder if this would look better and easy to see that the locking is 
> done correctly.
>
> lock_sock(sk);
> zapped = sock_flag(sk, SOCK_ZAPPED);
> release_sock(sk);
>
> if (zapped)
> return -EINVAL;
>
> Regards
>
> Marcel
>


[PATCH v2] Bluetooth: check for zapped sk before connecting

2021-03-23 Thread Archie Pusaka
From: Archie Pusaka 

There is a possibility of receiving a zapped sock on
l2cap_sock_connect(). This could lead to interesting crashes, one
such case is tearing down an already tore l2cap_sock as is happened
with this call trace:

__dump_stack lib/dump_stack.c:15 [inline]
dump_stack+0xc4/0x118 lib/dump_stack.c:56
register_lock_class kernel/locking/lockdep.c:792 [inline]
register_lock_class+0x239/0x6f6 kernel/locking/lockdep.c:742
__lock_acquire+0x209/0x1e27 kernel/locking/lockdep.c:3105
lock_acquire+0x29c/0x2fb kernel/locking/lockdep.c:3599
__raw_spin_lock_bh include/linux/spinlock_api_smp.h:137 [inline]
_raw_spin_lock_bh+0x38/0x47 kernel/locking/spinlock.c:175
spin_lock_bh include/linux/spinlock.h:307 [inline]
lock_sock_nested+0x44/0xfa net/core/sock.c:2518
l2cap_sock_teardown_cb+0x88/0x2fb net/bluetooth/l2cap_sock.c:1345
l2cap_chan_del+0xa3/0x383 net/bluetooth/l2cap_core.c:598
l2cap_chan_close+0x537/0x5dd net/bluetooth/l2cap_core.c:756
l2cap_chan_timeout+0x104/0x17e net/bluetooth/l2cap_core.c:429
process_one_work+0x7e3/0xcb0 kernel/workqueue.c:2064
worker_thread+0x5a5/0x773 kernel/workqueue.c:2196
kthread+0x291/0x2a6 kernel/kthread.c:211
ret_from_fork+0x4e/0x80 arch/x86/entry/entry_64.S:604

Signed-off-by: Archie Pusaka 
Reported-by: syzbot+abfc0f5e668d4099a...@syzkaller.appspotmail.com
Reviewed-by: Alain Michaud 
Reviewed-by: Abhishek Pandit-Subedi 
Reviewed-by: Guenter Roeck 
---

Changes in v2:
* Modify locking order for better visibility

 net/bluetooth/l2cap_sock.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index f1b1edd0b697..c99d65ef13b1 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -179,9 +179,17 @@ static int l2cap_sock_connect(struct socket *sock, struct 
sockaddr *addr,
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
struct sockaddr_l2 la;
int len, err = 0;
+   bool zapped;
 
BT_DBG("sk %p", sk);
 
+   lock_sock(sk);
+   zapped = sock_flag(sk, SOCK_ZAPPED);
+   release_sock(sk);
+
+   if (zapped)
+   return -EINVAL;
+
if (!addr || alen < offsetofend(struct sockaddr, sa_family) ||
addr->sa_family != AF_BLUETOOTH)
return -EINVAL;
-- 
2.31.0.291.g576ba9dcdaf-goog



[PATCH] Bluetooth: verify AMP hci_chan before amp_destroy

2021-03-22 Thread Archie Pusaka
From: Archie Pusaka 

hci_chan can be created in 2 places: hci_loglink_complete_evt() if
it is an AMP hci_chan, or l2cap_conn_add() otherwise. In theory,
Only AMP hci_chan should be removed by a call to
hci_disconn_loglink_complete_evt(). However, the controller might mess
up, call that function, and destroy an hci_chan which is not initiated
by hci_loglink_complete_evt().

This patch adds a verification that the destroyed hci_chan must have
been init'd by hci_loglink_complete_evt().

Example crash call trace:
Call Trace:
 __dump_stack lib/dump_stack.c:77 [inline]
 dump_stack+0xe3/0x144 lib/dump_stack.c:118
 print_address_description+0x67/0x22a mm/kasan/report.c:256
 kasan_report_error mm/kasan/report.c:354 [inline]
 kasan_report mm/kasan/report.c:412 [inline]
 kasan_report+0x251/0x28f mm/kasan/report.c:396
 hci_send_acl+0x3b/0x56e net/bluetooth/hci_core.c:4072
 l2cap_send_cmd+0x5af/0x5c2 net/bluetooth/l2cap_core.c:877
 l2cap_send_move_chan_cfm_icid+0x8e/0xb1 net/bluetooth/l2cap_core.c:4661
 l2cap_move_fail net/bluetooth/l2cap_core.c:5146 [inline]
 l2cap_move_channel_rsp net/bluetooth/l2cap_core.c:5185 [inline]
 l2cap_bredr_sig_cmd net/bluetooth/l2cap_core.c:5464 [inline]
 l2cap_sig_channel net/bluetooth/l2cap_core.c:5799 [inline]
 l2cap_recv_frame+0x1d12/0x51aa net/bluetooth/l2cap_core.c:7023
 l2cap_recv_acldata+0x2ea/0x693 net/bluetooth/l2cap_core.c:7596
 hci_acldata_packet net/bluetooth/hci_core.c:4606 [inline]
 hci_rx_work+0x2bd/0x45e net/bluetooth/hci_core.c:4796
 process_one_work+0x6f8/0xb50 kernel/workqueue.c:2175
 worker_thread+0x4fc/0x670 kernel/workqueue.c:2321
 kthread+0x2f0/0x304 kernel/kthread.c:253
 ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:415

Allocated by task 38:
 set_track mm/kasan/kasan.c:460 [inline]
 kasan_kmalloc+0x8d/0x9a mm/kasan/kasan.c:553
 kmem_cache_alloc_trace+0x102/0x129 mm/slub.c:2787
 kmalloc include/linux/slab.h:515 [inline]
 kzalloc include/linux/slab.h:709 [inline]
 hci_chan_create+0x86/0x26d net/bluetooth/hci_conn.c:1674
 l2cap_conn_add.part.0+0x1c/0x814 net/bluetooth/l2cap_core.c:7062
 l2cap_conn_add net/bluetooth/l2cap_core.c:7059 [inline]
 l2cap_connect_cfm+0x134/0x852 net/bluetooth/l2cap_core.c:7381
 hci_connect_cfm+0x9d/0x122 include/net/bluetooth/hci_core.h:1404
 hci_remote_ext_features_evt net/bluetooth/hci_event.c:4161 [inline]
 hci_event_packet+0x463f/0x72fa net/bluetooth/hci_event.c:5981
 hci_rx_work+0x197/0x45e net/bluetooth/hci_core.c:4791
 process_one_work+0x6f8/0xb50 kernel/workqueue.c:2175
 worker_thread+0x4fc/0x670 kernel/workqueue.c:2321
 kthread+0x2f0/0x304 kernel/kthread.c:253
 ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:415

Freed by task 1732:
 set_track mm/kasan/kasan.c:460 [inline]
 __kasan_slab_free mm/kasan/kasan.c:521 [inline]
 __kasan_slab_free+0x106/0x128 mm/kasan/kasan.c:493
 slab_free_hook mm/slub.c:1409 [inline]
 slab_free_freelist_hook+0xaa/0xf6 mm/slub.c:1436
 slab_free mm/slub.c:3009 [inline]
 kfree+0x182/0x21e mm/slub.c:3972
 hci_disconn_loglink_complete_evt net/bluetooth/hci_event.c:4891 [inline]
 hci_event_packet+0x6a1c/0x72fa net/bluetooth/hci_event.c:6050
 hci_rx_work+0x197/0x45e net/bluetooth/hci_core.c:4791
 process_one_work+0x6f8/0xb50 kernel/workqueue.c:2175
 worker_thread+0x4fc/0x670 kernel/workqueue.c:2321
 kthread+0x2f0/0x304 kernel/kthread.c:253
 ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:415

The buggy address belongs to the object at 8881d7af9180
 which belongs to the cache kmalloc-128 of size 128
The buggy address is located 24 bytes inside of
 128-byte region [8881d7af9180, 8881d7af9200)
The buggy address belongs to the page:
page:ea00075ebe40 count:1 mapcount:0 mapping:8881da403200 index:0x0
flags: 0x8200(slab)
raw: 8200 dead0100 dead0200 8881da403200
raw:  80150015 0001 
page dumped because: kasan: bad access detected

Memory state around the buggy address:
 8881d7af9080: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
 8881d7af9100: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
>8881d7af9180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
 8881d7af9200: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 8881d7af9280: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc

Signed-off-by: Archie Pusaka 
Reported-by: syzbot+98228e7407314d2d4...@syzkaller.appspotmail.com
Reviewed-by: Alain Michaud 
Reviewed-by: Abhishek Pandit-Subedi 
---

 include/net/bluetooth/hci_core.h | 1 +
 net/bluetooth/hci_event.c| 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index ebdd4afe30d2..ca4ac6603b9a 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -704,6 +704,7 @@ struct hci_chan {
struct sk_buff_head data_q;
unsigned intsent;
__u8state;
+   boolamp;
 };
 
 str

[PATCH] Bluetooth: Set CONF_NOT_COMPLETE as l2cap_chan default

2021-03-22 Thread Archie Pusaka
From: Archie Pusaka 

Currently l2cap_chan_set_defaults() reset chan->conf_state to zero.
However, there is a flag CONF_NOT_COMPLETE which is set when
creating the l2cap_chan. It is suggested that the flag should be
cleared when l2cap_chan is ready, but when l2cap_chan_set_defaults()
is called, l2cap_chan is not yet ready. Therefore, we must set this
flag as the default.

Example crash call trace:
__dump_stack lib/dump_stack.c:15 [inline]
dump_stack+0xc4/0x118 lib/dump_stack.c:56
panic+0x1c6/0x38b kernel/panic.c:117
__warn+0x170/0x1b9 kernel/panic.c:471
warn_slowpath_fmt+0xc7/0xf8 kernel/panic.c:494
debug_print_object+0x175/0x193 lib/debugobjects.c:260
debug_object_assert_init+0x171/0x1bf lib/debugobjects.c:614
debug_timer_assert_init kernel/time/timer.c:629 [inline]
debug_assert_init kernel/time/timer.c:677 [inline]
del_timer+0x7c/0x179 kernel/time/timer.c:1034
try_to_grab_pending+0x81/0x2e5 kernel/workqueue.c:1230
cancel_delayed_work+0x7c/0x1c4 kernel/workqueue.c:2929
l2cap_clear_timer+0x1e/0x41 include/net/bluetooth/l2cap.h:834
l2cap_chan_del+0x2d8/0x37e net/bluetooth/l2cap_core.c:640
l2cap_chan_close+0x532/0x5d8 net/bluetooth/l2cap_core.c:756
l2cap_sock_shutdown+0x806/0x969 net/bluetooth/l2cap_sock.c:1174
l2cap_sock_release+0x64/0x14d net/bluetooth/l2cap_sock.c:1217
__sock_release+0xda/0x217 net/socket.c:580
sock_close+0x1b/0x1f net/socket.c:1039
__fput+0x322/0x55c fs/file_table.c:208
fput+0x17/0x19 fs/file_table.c:244
task_work_run+0x19b/0x1d3 kernel/task_work.c:115
exit_task_work include/linux/task_work.h:21 [inline]
do_exit+0xe4c/0x204a kernel/exit.c:766
do_group_exit+0x291/0x291 kernel/exit.c:891
get_signal+0x749/0x1093 kernel/signal.c:2396
do_signal+0xa5/0xcdb arch/x86/kernel/signal.c:737
exit_to_usermode_loop arch/x86/entry/common.c:243 [inline]
prepare_exit_to_usermode+0xed/0x235 arch/x86/entry/common.c:277
syscall_return_slowpath+0x3a7/0x3b3 arch/x86/entry/common.c:348
int_ret_from_sys_call+0x25/0xa3

Signed-off-by: Archie Pusaka 
Reported-by: syzbot+338f014a98367a08a...@syzkaller.appspotmail.com
Reviewed-by: Alain Michaud 
Reviewed-by: Abhishek Pandit-Subedi 
Reviewed-by: Guenter Roeck 
---

 net/bluetooth/l2cap_core.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 374cc32d7138..59ab9689b37d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -516,7 +516,9 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan)
chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
+
chan->conf_state = 0;
+   set_bit(CONF_NOT_COMPLETE, >conf_state);
 
set_bit(FLAG_FORCE_ACTIVE, >flags);
 }
-- 
2.31.0.rc2.261.g7f71774620-goog



[PATCH] Bluetooth: check for zapped sk before connecting

2021-03-22 Thread Archie Pusaka
From: Archie Pusaka 

There is a possibility of receiving a zapped sock on
l2cap_sock_connect(). This could lead to interesting crashes, one
such case is tearing down an already tore l2cap_sock as is happened
with this call trace:

__dump_stack lib/dump_stack.c:15 [inline]
dump_stack+0xc4/0x118 lib/dump_stack.c:56
register_lock_class kernel/locking/lockdep.c:792 [inline]
register_lock_class+0x239/0x6f6 kernel/locking/lockdep.c:742
__lock_acquire+0x209/0x1e27 kernel/locking/lockdep.c:3105
lock_acquire+0x29c/0x2fb kernel/locking/lockdep.c:3599
__raw_spin_lock_bh include/linux/spinlock_api_smp.h:137 [inline]
_raw_spin_lock_bh+0x38/0x47 kernel/locking/spinlock.c:175
spin_lock_bh include/linux/spinlock.h:307 [inline]
lock_sock_nested+0x44/0xfa net/core/sock.c:2518
l2cap_sock_teardown_cb+0x88/0x2fb net/bluetooth/l2cap_sock.c:1345
l2cap_chan_del+0xa3/0x383 net/bluetooth/l2cap_core.c:598
l2cap_chan_close+0x537/0x5dd net/bluetooth/l2cap_core.c:756
l2cap_chan_timeout+0x104/0x17e net/bluetooth/l2cap_core.c:429
process_one_work+0x7e3/0xcb0 kernel/workqueue.c:2064
worker_thread+0x5a5/0x773 kernel/workqueue.c:2196
kthread+0x291/0x2a6 kernel/kthread.c:211
ret_from_fork+0x4e/0x80 arch/x86/entry/entry_64.S:604

Signed-off-by: Archie Pusaka 
Reported-by: syzbot+abfc0f5e668d4099a...@syzkaller.appspotmail.com
Reviewed-by: Alain Michaud 
Reviewed-by: Abhishek Pandit-Subedi 
Reviewed-by: Guenter Roeck 
---

 net/bluetooth/l2cap_sock.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index f1b1edd0b697..b86fd8cc4dc1 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -182,6 +182,13 @@ static int l2cap_sock_connect(struct socket *sock, struct 
sockaddr *addr,
 
BT_DBG("sk %p", sk);
 
+   lock_sock(sk);
+   if (sock_flag(sk, SOCK_ZAPPED)) {
+   release_sock(sk);
+   return -EINVAL;
+   }
+   release_sock(sk);
+
if (!addr || alen < offsetofend(struct sockaddr, sa_family) ||
addr->sa_family != AF_BLUETOOTH)
return -EINVAL;
-- 
2.31.0.rc2.261.g7f71774620-goog



[PATCH v6 0/7] MSFT offloading support for advertisement monitor

2021-01-22 Thread Archie Pusaka
From: Archie Pusaka 


Hi linux-bluetooth,

This series of patches manages the hardware offloading part of MSFT
extension API. The full documentation can be accessed by this link:
https://docs.microsoft.com/en-us/windows-hardware/drivers/bluetooth/microsoft-defined-bluetooth-hci-commands-and-events

Only four of the HCI commands are planned to be implemented:
HCI_VS_MSFT_Read_Supported_Features (implemented in previous patch),
HCI_VS_MSFT_LE_Monitor_Advertisement,
HCI_VS_MSFT_LE_Cancel_Monitor_Advertisement, and
HCI_VS_MSFT_LE_Set_Advertisement_Filter_Enable.
These are the commands which would be used for advertisement monitor
feature. Only if the controller supports the MSFT extension would
these commands be sent. Otherwise, software-based monitoring would be
performed in the user space instead.

Thanks in advance for your feedback!

Archie

Changes in v6:
* New patch "advmon offload MSFT interleave scanning integration"
* New patch "disable advertisement filters during suspend"

Changes in v5:
* Discard struct flags on msft_data and use it's members directly

Changes in v4:
* Change the logic of merging add_adv_patterns_monitor with rssi
* Aligning variable declaration on mgmt.h
* Replacing the usage of BT_DBG with bt_dev_dbg

Changes in v3:
* Flips the order of rssi and pattern_count on mgmt struct
* Fix return type of msft_remove_monitor

Changes in v2:
* Add a new opcode instead of modifying an existing one
* Also implement the new MGMT opcode and merge the functionality with
  the old one.

Archie Pusaka (6):
  Bluetooth: advmon offload MSFT add rssi support
  Bluetooth: advmon offload MSFT add monitor
  Bluetooth: advmon offload MSFT remove monitor
  Bluetooth: advmon offload MSFT handle controller reset
  Bluetooth: advmon offload MSFT handle filter enablement
  Bluetooth: advmon offload MSFT interleave scanning integration

Howard Chung (1):
  Bluetooth: disable advertisement filters during suspend

 include/net/bluetooth/hci_core.h |  36 ++-
 include/net/bluetooth/mgmt.h |  16 ++
 net/bluetooth/hci_core.c | 174 +---
 net/bluetooth/hci_request.c  |  49 +++-
 net/bluetooth/mgmt.c | 391 +++---
 net/bluetooth/msft.c | 460 ++-
 net/bluetooth/msft.h |  30 ++
 7 files changed, 1015 insertions(+), 141 deletions(-)

-- 
2.30.0.280.ga3ce27912f-goog



[PATCH v6 3/7] Bluetooth: advmon offload MSFT remove monitor

2021-01-22 Thread Archie Pusaka
From: Archie Pusaka 

Implements the monitor removal functionality for advertising monitor
offloading to MSFT controllers. Supply handle = 0 to remove all
monitors.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 
Reported-by: kernel test robot 
Reported-by: Dan Carpenter 

---

(no changes since v3)

Changes in v3:
* Fix return type of msft_remove_monitor

 include/net/bluetooth/hci_core.h |   8 +-
 net/bluetooth/hci_core.c | 119 +++--
 net/bluetooth/mgmt.c | 110 +-
 net/bluetooth/msft.c | 127 ++-
 net/bluetooth/msft.h |   9 +++
 5 files changed, 323 insertions(+), 50 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 879d1e38ce96..29cfc6a2d689 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1332,11 +1332,13 @@ int hci_remove_adv_instance(struct hci_dev *hdev, u8 
instance);
 void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired);
 
 void hci_adv_monitors_clear(struct hci_dev *hdev);
-void hci_free_adv_monitor(struct adv_monitor *monitor);
+void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
 int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
 bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
int *err);
-int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle);
+bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err);
+bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err);
 bool hci_is_adv_monitoring(struct hci_dev *hdev);
 int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev);
 
@@ -1813,8 +1815,10 @@ void mgmt_advertising_added(struct sock *sk, struct 
hci_dev *hdev,
u8 instance);
 void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
  u8 instance);
+void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle);
 int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
 int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
 
 u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
  u16 to_multiplier);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 625298f64a20..b0a63f643a07 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3051,12 +3051,15 @@ void hci_adv_monitors_clear(struct hci_dev *hdev)
int handle;
 
idr_for_each_entry(>adv_monitors_idr, monitor, handle)
-   hci_free_adv_monitor(monitor);
+   hci_free_adv_monitor(hdev, monitor);
 
idr_destroy(>adv_monitors_idr);
 }
 
-void hci_free_adv_monitor(struct adv_monitor *monitor)
+/* Frees the monitor structure and do some bookkeepings.
+ * This function requires the caller holds hdev->lock.
+ */
+void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
 {
struct adv_pattern *pattern;
struct adv_pattern *tmp;
@@ -3064,8 +3067,18 @@ void hci_free_adv_monitor(struct adv_monitor *monitor)
if (!monitor)
return;
 
-   list_for_each_entry_safe(pattern, tmp, >patterns, list)
+   list_for_each_entry_safe(pattern, tmp, >patterns, list) {
+   list_del(>list);
kfree(pattern);
+   }
+
+   if (monitor->handle)
+   idr_remove(>adv_monitors_idr, monitor->handle);
+
+   if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED) {
+   hdev->adv_monitors_cnt--;
+   mgmt_adv_monitor_removed(hdev, monitor->handle);
+   }
 
kfree(monitor);
 }
@@ -3075,6 +3088,11 @@ int hci_add_adv_patterns_monitor_complete(struct hci_dev 
*hdev, u8 status)
return mgmt_add_adv_patterns_monitor_complete(hdev, status);
 }
 
+int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
+{
+   return mgmt_remove_adv_monitor_complete(hdev, status);
+}
+
 /* Assigns handle to a monitor, and if offloading is supported and power is on,
  * also attempts to forward the request to the controller.
  * Returns true if request is forwarded (result is pending), false otherwise.
@@ -3122,39 +3140,94 @@ bool hci_add_adv_monitor(struct hci_dev *hdev, struct 
adv_monitor *monitor,
return (*err == 0);
 }
 
-static int free_adv_monitor(int id, void *ptr, void *data)
+/* Attempts to tell the controller and free the monitor. If somehow the
+ * controller doesn't have a corresponding handle, remove anyway.
+ * Returns true if request is forwarded (result is pending), false otherwise.
+ * This function 

[PATCH v6 2/7] Bluetooth: advmon offload MSFT add monitor

2021-01-22 Thread Archie Pusaka
From: Archie Pusaka 

Enables advertising monitor offloading to the controller, if MSFT
extension is supported. The kernel won't adjust the monitor parameters
to match what the controller supports - that is the user space's
responsibility.

This patch only manages the addition of monitors. Monitor removal is
going to be handled by another patch.

Signed-off-by: Archie Pusaka 
Reviewed-by: Manish Mandlik 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

(no changes since v4)

Changes in v4:
* Replacing the usage of BT_DBG with bt_dev_dbg

Changes in v2:
* Also implement the new MGMT opcode and merge the functionality with
  the old one.

 include/net/bluetooth/hci_core.h |  17 ++-
 net/bluetooth/hci_core.c |  55 +++--
 net/bluetooth/mgmt.c | 114 +-
 net/bluetooth/msft.c | 201 ++-
 net/bluetooth/msft.h |  12 ++
 5 files changed, 356 insertions(+), 43 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 8b7cf3620938..879d1e38ce96 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -261,13 +261,20 @@ struct adv_rssi_thresholds {
 struct adv_monitor {
struct list_head patterns;
struct adv_rssi_thresholds rssi;
-   boolactive;
__u16   handle;
+
+   enum {
+   ADV_MONITOR_STATE_NOT_REGISTERED,
+   ADV_MONITOR_STATE_REGISTERED,
+   ADV_MONITOR_STATE_OFFLOADED
+   } state;
 };
 
 #define HCI_MIN_ADV_MONITOR_HANDLE 1
-#define HCI_MAX_ADV_MONITOR_NUM_HANDLES32
+#define HCI_MAX_ADV_MONITOR_NUM_HANDLES32
 #define HCI_MAX_ADV_MONITOR_NUM_PATTERNS   16
+#define HCI_ADV_MONITOR_EXT_NONE   1
+#define HCI_ADV_MONITOR_EXT_MSFT   2
 
 #define HCI_MAX_SHORT_NAME_LENGTH  10
 
@@ -1326,9 +1333,12 @@ void hci_adv_instances_set_rpa_expired(struct hci_dev 
*hdev, bool rpa_expired);
 
 void hci_adv_monitors_clear(struct hci_dev *hdev);
 void hci_free_adv_monitor(struct adv_monitor *monitor);
-int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
+int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
+   int *err);
 int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle);
 bool hci_is_adv_monitoring(struct hci_dev *hdev);
+int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev);
 
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
 
@@ -1804,6 +1814,7 @@ void mgmt_advertising_added(struct sock *sk, struct 
hci_dev *hdev,
 void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
  u8 instance);
 int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
+int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
 
 u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
  u16 to_multiplier);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9d2c9a1c552f..625298f64a20 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3070,27 +3070,56 @@ void hci_free_adv_monitor(struct adv_monitor *monitor)
kfree(monitor);
 }
 
-/* This function requires the caller holds hdev->lock */
-int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
+int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)
+{
+   return mgmt_add_adv_patterns_monitor_complete(hdev, status);
+}
+
+/* Assigns handle to a monitor, and if offloading is supported and power is on,
+ * also attempts to forward the request to the controller.
+ * Returns true if request is forwarded (result is pending), false otherwise.
+ * This function requires the caller holds hdev->lock.
+ */
+bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
+int *err)
 {
int min, max, handle;
 
-   if (!monitor)
-   return -EINVAL;
+   *err = 0;
+
+   if (!monitor) {
+   *err = -EINVAL;
+   return false;
+   }
 
min = HCI_MIN_ADV_MONITOR_HANDLE;
max = HCI_MIN_ADV_MONITOR_HANDLE + HCI_MAX_ADV_MONITOR_NUM_HANDLES;
handle = idr_alloc(>adv_monitors_idr, monitor, min, max,
   GFP_KERNEL);
-   if (handle < 0)
-   return handle;
+   if (handle < 0) {
+   *err = handle;
+   return false;
+   }
 
-   hdev->adv_monitors_cnt++;
monitor->handle = handle;
 
-   hci_update_background_scan(hdev);
+   if (!hdev_is_powered(hdev))
+   return false;
 
-   return 0;
+   switch (hci_get_adv_monitor_offload_ext(hdev)) {
+   case HCI

[PATCH v6 1/7] Bluetooth: advmon offload MSFT add rssi support

2021-01-22 Thread Archie Pusaka
From: Archie Pusaka 

MSFT needs rssi parameter for monitoring advertisement packet,
therefore we should supply them from mgmt. This adds a new opcode
to add advertisement monitor with rssi parameters.

Signed-off-by: Archie Pusaka 
Reviewed-by: Manish Mandlik 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

(no changes since v4)

Changes in v4:
* Change the logic of merging add_adv_patterns_monitor with rssi
* Aligning variable declaration on mgmt.h

Changes in v3:
* Flips the order of rssi and pattern_count on mgmt struct

Changes in v2:
* Add a new opcode instead of modifying an existing one

 include/net/bluetooth/hci_core.h |   9 ++
 include/net/bluetooth/mgmt.h |  16 +++
 net/bluetooth/mgmt.c | 225 +--
 3 files changed, 178 insertions(+), 72 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 677a8c50b2ad..8b7cf3620938 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -250,8 +250,17 @@ struct adv_pattern {
__u8 value[HCI_MAX_AD_LENGTH];
 };
 
+struct adv_rssi_thresholds {
+   __s8 low_threshold;
+   __s8 high_threshold;
+   __u16 low_threshold_timeout;
+   __u16 high_threshold_timeout;
+   __u8 sampling_period;
+};
+
 struct adv_monitor {
struct list_head patterns;
+   struct adv_rssi_thresholds rssi;
boolactive;
__u16   handle;
 };
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index f9a6638e20b3..839a2028009e 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -821,6 +821,22 @@ struct mgmt_rp_add_ext_adv_data {
__u8instance;
 } __packed;
 
+struct mgmt_adv_rssi_thresholds {
+   __s8high_threshold;
+   __le16  high_threshold_timeout;
+   __s8low_threshold;
+   __le16  low_threshold_timeout;
+   __u8sampling_period;
+} __packed;
+
+#define MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI  0x0056
+struct mgmt_cp_add_adv_patterns_monitor_rssi {
+   struct mgmt_adv_rssi_thresholds rssi;
+   __u8pattern_count;
+   struct mgmt_adv_pattern patterns[];
+} __packed;
+#define MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE8
+
 #define MGMT_EV_CMD_COMPLETE   0x0001
 struct mgmt_ev_cmd_complete {
__le16  opcode;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 608dda5403b7..72d37c80e071 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -124,6 +124,7 @@ static const u16 mgmt_commands[] = {
MGMT_OP_REMOVE_ADV_MONITOR,
MGMT_OP_ADD_EXT_ADV_PARAMS,
MGMT_OP_ADD_EXT_ADV_DATA,
+   MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI,
 };
 
 static const u16 mgmt_events[] = {
@@ -4225,75 +4226,15 @@ static int read_adv_mon_features(struct sock *sk, 
struct hci_dev *hdev,
return err;
 }
 
-static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
-   void *data, u16 len)
+static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
+ struct adv_monitor *m, u8 status, u16 op)
 {
-   struct mgmt_cp_add_adv_patterns_monitor *cp = data;
struct mgmt_rp_add_adv_patterns_monitor rp;
-   struct adv_monitor *m = NULL;
-   struct adv_pattern *p = NULL;
-   unsigned int mp_cnt = 0, prev_adv_monitors_cnt;
-   __u8 cp_ofst = 0, cp_len = 0;
-   int err, i;
-
-   BT_DBG("request for %s", hdev->name);
-
-   if (len <= sizeof(*cp) || cp->pattern_count == 0) {
-   err = mgmt_cmd_status(sk, hdev->id,
- MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
- MGMT_STATUS_INVALID_PARAMS);
-   goto failed;
-   }
-
-   m = kmalloc(sizeof(*m), GFP_KERNEL);
-   if (!m) {
-   err = -ENOMEM;
-   goto failed;
-   }
-
-   INIT_LIST_HEAD(>patterns);
-   m->active = false;
-
-   for (i = 0; i < cp->pattern_count; i++) {
-   if (++mp_cnt > HCI_MAX_ADV_MONITOR_NUM_PATTERNS) {
-   err = mgmt_cmd_status(sk, hdev->id,
- MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
- MGMT_STATUS_INVALID_PARAMS);
-   goto failed;
-   }
-
-   cp_ofst = cp->patterns[i].offset;
-   cp_len = cp->patterns[i].length;
-   if (cp_ofst >= HCI_MAX_AD_LENGTH ||
-   cp_len > HCI_MAX_AD_LENGTH ||
-   (cp_ofst + cp_len) > HCI_MAX_AD_LENGTH) {
-   err = mgmt_cmd_status(sk, hdev->id,
- MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
- MGMT_STATUS_INVALID_PARAMS);
-   go

[PATCH v6 6/7] Bluetooth: advmon offload MSFT interleave scanning integration

2021-01-22 Thread Archie Pusaka
From: Archie Pusaka 

When MSFT extension is supported, we don't have to interleave the scan
as we could just do allowlist scan.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 

---

Changes in v6:
* New patch "advmon offload MSFT interleave scanning integration"

 net/bluetooth/hci_request.c | 20 +++-
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index 5aa7bd5030a2..d29a44d77b4e 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -404,13 +404,18 @@ static void cancel_interleave_scan(struct hci_dev *hdev)
  */
 static bool __hci_update_interleaved_scan(struct hci_dev *hdev)
 {
-   /* If there is at least one ADV monitors and one pending LE connection
-* or one device to be scanned for, we should alternate between
-* allowlist scan and one without any filters to save power.
+   /* Do interleaved scan only if all of the following are true:
+* - There is at least one ADV monitor
+* - At least one pending LE connection or one device to be scanned for
+* - Monitor offloading is not supported
+* If so, we should alternate between allowlist scan and one without
+* any filters to save power.
 */
bool use_interleaving = hci_is_adv_monitoring(hdev) &&
!(list_empty(>pend_le_conns) &&
- list_empty(>pend_le_reports));
+ list_empty(>pend_le_reports)) &&
+   hci_get_adv_monitor_offload_ext(hdev) ==
+   HCI_ADV_MONITOR_EXT_NONE;
bool is_interleaving = is_interleave_scanning(hdev);
 
if (use_interleaving && !is_interleaving) {
@@ -899,14 +904,11 @@ static u8 update_white_list(struct hci_request *req)
 
/* Use the allowlist unless the following conditions are all true:
 * - We are not currently suspending
-* - There are 1 or more ADV monitors registered
+* - There are 1 or more ADV monitors registered and it's not offloaded
 * - Interleaved scanning is not currently using the allowlist
-*
-* Once the controller offloading of advertisement monitor is in place,
-* the above condition should include the support of MSFT extension
-* support.
 */
if (!idr_is_empty(>adv_monitors_idr) && !hdev->suspended &&
+   hci_get_adv_monitor_offload_ext(hdev) == HCI_ADV_MONITOR_EXT_NONE &&
hdev->interleave_scan_state != INTERLEAVE_SCAN_ALLOWLIST)
return 0x00;
 
-- 
2.30.0.280.ga3ce27912f-goog



[PATCH v6 7/7] Bluetooth: disable advertisement filters during suspend

2021-01-22 Thread Archie Pusaka
From: Howard Chung 

This adds logic to disable and reenable advertisement filters during
suspend and resume. After this patch, we would only receive packets from
devices in allow list during suspend.

Signed-off-by: Howard Chung 
Reviewed-by: Abhishek Pandit-Subedi 
---

Changes in v6:
* New patch "disable advertisement filters during suspend"

 include/net/bluetooth/hci_core.h |  2 ++
 net/bluetooth/hci_request.c  | 29 +
 net/bluetooth/msft.c | 17 -
 net/bluetooth/msft.h |  3 +++
 4 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 29cfc6a2d689..fd1d10fe2f11 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -105,6 +105,8 @@ enum suspend_tasks {
SUSPEND_POWERING_DOWN,
 
SUSPEND_PREPARE_NOTIFIER,
+
+   SUSPEND_SET_ADV_FILTER,
__SUSPEND_NUM_TASKS
 };
 
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index d29a44d77b4e..e55976db4403 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -29,6 +29,7 @@
 
 #include "smp.h"
 #include "hci_request.h"
+#include "msft.h"
 
 #define HCI_REQ_DONE 0
 #define HCI_REQ_PEND 1
@@ -1242,6 +1243,29 @@ static void suspend_req_complete(struct hci_dev *hdev, 
u8 status, u16 opcode)
clear_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
wake_up(>suspend_wait_q);
}
+
+   if (test_bit(SUSPEND_SET_ADV_FILTER, hdev->suspend_tasks)) {
+   clear_bit(SUSPEND_SET_ADV_FILTER, hdev->suspend_tasks);
+   wake_up(>suspend_wait_q);
+   }
+}
+
+static void hci_req_add_set_adv_filter_enable(struct hci_request *req,
+ bool enable)
+{
+   struct hci_dev *hdev = req->hdev;
+
+   switch (hci_get_adv_monitor_offload_ext(hdev)) {
+   case HCI_ADV_MONITOR_EXT_MSFT:
+   msft_req_add_set_filter_enable(req, enable);
+   break;
+   default:
+   return;
+   }
+
+   /* No need to block when enabling since it's on resume path */
+   if (hdev->suspended && !enable)
+   set_bit(SUSPEND_SET_ADV_FILTER, hdev->suspend_tasks);
 }
 
 /* Call with hci_dev_lock */
@@ -1301,6 +1325,9 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum 
suspended_state next)
hci_req_add_le_scan_disable(, false);
}
 
+   /* Disable advertisement filters */
+   hci_req_add_set_adv_filter_enable(, false);
+
/* Mark task needing completion */
set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
 
@@ -1340,6 +1367,8 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum 
suspended_state next)
hci_req_clear_event_filter();
/* Reset passive/background scanning to normal */
__hci_update_background_scan();
+   /* Enable all of the advertisement filters */
+   hci_req_add_set_adv_filter_enable(, true);
 
/* Unpause directed advertising */
hdev->advertising_paused = false;
diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index b2ef654b1d3d..47b104f318e9 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -579,9 +579,19 @@ int msft_remove_monitor(struct hci_dev *hdev, struct 
adv_monitor *monitor,
return err;
 }
 
-int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
+void msft_req_add_set_filter_enable(struct hci_request *req, bool enable)
 {
+   struct hci_dev *hdev = req->hdev;
struct msft_cp_le_set_advertisement_filter_enable cp;
+
+   cp.sub_opcode = MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE;
+   cp.enable = enable;
+
+   hci_req_add(req, hdev->msft_opcode, sizeof(cp), );
+}
+
+int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
+{
struct hci_request req;
struct msft_data *msft = hdev->msft_data;
int err;
@@ -589,11 +599,8 @@ int msft_set_filter_enable(struct hci_dev *hdev, bool 
enable)
if (!msft)
return -EOPNOTSUPP;
 
-   cp.sub_opcode = MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE;
-   cp.enable = enable;
-
hci_req_init(, hdev);
-   hci_req_add(, hdev->msft_opcode, sizeof(cp), );
+   msft_req_add_set_filter_enable(, enable);
err = hci_req_run_skb(, msft_le_set_advertisement_filter_enable_cb);
 
return err;
diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
index f8e4d3a6d641..88ed613dfa08 100644
--- a/net/bluetooth/msft.h
+++ b/net/bluetooth/msft.h
@@ -20,6 +20,7 @@ __u64 msft_get_features(struct hci_dev *hdev);
 int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor 
*monitor);
 int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
u16 handle);
+void 

[PATCH v6 5/7] Bluetooth: advmon offload MSFT handle filter enablement

2021-01-22 Thread Archie Pusaka
From: Archie Pusaka 

Implements the feature to disable/enable the filter used for
advertising monitor on MSFT controller, effectively have the same
effect as "remove all monitors" and "add all previously removed
monitors".

This feature would be needed when suspending, where we would not want
to get packets from anything outside the allowlist. Note that the
integration with the suspending part is not included in this patch.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

(no changes since v1)

 net/bluetooth/msft.c | 67 
 net/bluetooth/msft.h |  6 
 2 files changed, 73 insertions(+)

diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index d25c6936daa4..b2ef654b1d3d 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -69,6 +69,17 @@ struct msft_rp_le_cancel_monitor_advertisement {
__u8 sub_opcode;
 } __packed;
 
+#define MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE 0x05
+struct msft_cp_le_set_advertisement_filter_enable {
+   __u8 sub_opcode;
+   __u8 enable;
+} __packed;
+
+struct msft_rp_le_set_advertisement_filter_enable {
+   __u8 status;
+   __u8 sub_opcode;
+} __packed;
+
 struct msft_monitor_advertisement_handle_data {
__u8  msft_handle;
__u16 mgmt_handle;
@@ -83,6 +94,7 @@ struct msft_data {
__u16 pending_add_handle;
__u16 pending_remove_handle;
__u8 reregistering;
+   __u8 filter_enabled;
 };
 
 static int __msft_add_monitor_pattern(struct hci_dev *hdev,
@@ -190,6 +202,7 @@ void msft_do_open(struct hci_dev *hdev)
 
if (msft_monitor_supported(hdev)) {
msft->reregistering = true;
+   msft_set_filter_enable(hdev, true);
reregister_monitor_on_restart(hdev, 0);
}
 }
@@ -395,6 +408,40 @@ static void msft_le_cancel_monitor_advertisement_cb(struct 
hci_dev *hdev,
hci_remove_adv_monitor_complete(hdev, status);
 }
 
+static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev,
+  u8 status, u16 opcode,
+  struct sk_buff *skb)
+{
+   struct msft_cp_le_set_advertisement_filter_enable *cp;
+   struct msft_rp_le_set_advertisement_filter_enable *rp;
+   struct msft_data *msft = hdev->msft_data;
+
+   rp = (struct msft_rp_le_set_advertisement_filter_enable *)skb->data;
+   if (skb->len < sizeof(*rp))
+   return;
+
+   /* Error 0x0C would be returned if the filter enabled status is
+* already set to whatever we were trying to set.
+* Although the default state should be disabled, some controller set
+* the initial value to enabled. Because there is no way to know the
+* actual initial value before sending this command, here we also treat
+* error 0x0C as success.
+*/
+   if (status != 0x00 && status != 0x0C)
+   return;
+
+   hci_dev_lock(hdev);
+
+   cp = hci_sent_cmd_data(hdev, hdev->msft_opcode);
+   msft->filter_enabled = cp->enable;
+
+   if (status == 0x0C)
+   bt_dev_warn(hdev, "MSFT filter_enable is already %s",
+   cp->enable ? "on" : "off");
+
+   hci_dev_unlock(hdev);
+}
+
 static bool msft_monitor_rssi_valid(struct adv_monitor *monitor)
 {
struct adv_rssi_thresholds *r = >rssi;
@@ -531,3 +578,23 @@ int msft_remove_monitor(struct hci_dev *hdev, struct 
adv_monitor *monitor,
 
return err;
 }
+
+int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
+{
+   struct msft_cp_le_set_advertisement_filter_enable cp;
+   struct hci_request req;
+   struct msft_data *msft = hdev->msft_data;
+   int err;
+
+   if (!msft)
+   return -EOPNOTSUPP;
+
+   cp.sub_opcode = MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE;
+   cp.enable = enable;
+
+   hci_req_init(, hdev);
+   hci_req_add(, hdev->msft_opcode, sizeof(cp), );
+   err = hci_req_run_skb(, msft_le_set_advertisement_filter_enable_cb);
+
+   return err;
+}
diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
index 6f126a1f1688..f8e4d3a6d641 100644
--- a/net/bluetooth/msft.h
+++ b/net/bluetooth/msft.h
@@ -20,6 +20,7 @@ __u64 msft_get_features(struct hci_dev *hdev);
 int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor 
*monitor);
 int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
u16 handle);
+int msft_set_filter_enable(struct hci_dev *hdev, bool enable);
 
 #else
 
@@ -45,4 +46,9 @@ static inline int msft_remove_monitor(struct hci_dev *hdev,
return -EOPNOTSUPP;
 }
 
+static inline int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
+{
+   return -EOPNOTSUPP;
+}
+
 #endif
-- 
2.30.0.280.ga3ce27912f-goog



[PATCH v6 4/7] Bluetooth: advmon offload MSFT handle controller reset

2021-01-22 Thread Archie Pusaka
From: Archie Pusaka 

When the controller is powered off, the registered advertising monitor
is removed from the controller. This patch handles the re-registration
of those monitors when the power is on.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

(no changes since v5)

Changes in v5:
* Discard struct flags on msft_data and use it's members directly

 net/bluetooth/msft.c | 76 +---
 1 file changed, 71 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index f5aa0e3b1b9b..d25c6936daa4 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -82,8 +82,12 @@ struct msft_data {
struct list_head handle_map;
__u16 pending_add_handle;
__u16 pending_remove_handle;
+   __u8 reregistering;
 };
 
+static int __msft_add_monitor_pattern(struct hci_dev *hdev,
+ struct adv_monitor *monitor);
+
 bool msft_monitor_supported(struct hci_dev *hdev)
 {
return !!(msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR);
@@ -134,6 +138,35 @@ static bool read_supported_features(struct hci_dev *hdev,
return false;
 }
 
+/* This function requires the caller holds hdev->lock */
+static void reregister_monitor_on_restart(struct hci_dev *hdev, int handle)
+{
+   struct adv_monitor *monitor;
+   struct msft_data *msft = hdev->msft_data;
+   int err;
+
+   while (1) {
+   monitor = idr_get_next(>adv_monitors_idr, );
+   if (!monitor) {
+   /* All monitors have been reregistered */
+   msft->reregistering = false;
+   hci_update_background_scan(hdev);
+   return;
+   }
+
+   msft->pending_add_handle = (u16)handle;
+   err = __msft_add_monitor_pattern(hdev, monitor);
+
+   /* If success, we return and wait for monitor added callback */
+   if (!err)
+   return;
+
+   /* Otherwise remove the monitor and keep registering */
+   hci_free_adv_monitor(hdev, monitor);
+   handle++;
+   }
+}
+
 void msft_do_open(struct hci_dev *hdev)
 {
struct msft_data *msft;
@@ -154,12 +187,18 @@ void msft_do_open(struct hci_dev *hdev)
 
INIT_LIST_HEAD(>handle_map);
hdev->msft_data = msft;
+
+   if (msft_monitor_supported(hdev)) {
+   msft->reregistering = true;
+   reregister_monitor_on_restart(hdev, 0);
+   }
 }
 
 void msft_do_close(struct hci_dev *hdev)
 {
struct msft_data *msft = hdev->msft_data;
struct msft_monitor_advertisement_handle_data *handle_data, *tmp;
+   struct adv_monitor *monitor;
 
if (!msft)
return;
@@ -169,6 +208,12 @@ void msft_do_close(struct hci_dev *hdev)
hdev->msft_data = NULL;
 
list_for_each_entry_safe(handle_data, tmp, >handle_map, list) {
+   monitor = idr_find(>adv_monitors_idr,
+  handle_data->mgmt_handle);
+
+   if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED)
+   monitor->state = ADV_MONITOR_STATE_REGISTERED;
+
list_del(_data->list);
kfree(handle_data);
}
@@ -282,9 +327,15 @@ static void msft_le_monitor_advertisement_cb(struct 
hci_dev *hdev,
if (status && monitor)
hci_free_adv_monitor(hdev, monitor);
 
+   /* If in restart/reregister sequence, keep registering. */
+   if (msft->reregistering)
+   reregister_monitor_on_restart(hdev,
+ msft->pending_add_handle + 1);
+
hci_dev_unlock(hdev);
 
-   hci_add_adv_patterns_monitor_complete(hdev, status);
+   if (!msft->reregistering)
+   hci_add_adv_patterns_monitor_complete(hdev, status);
 }
 
 static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
@@ -374,7 +425,8 @@ static bool msft_monitor_pattern_valid(struct adv_monitor 
*monitor)
 }
 
 /* This function requires the caller holds hdev->lock */
-int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor)
+static int __msft_add_monitor_pattern(struct hci_dev *hdev,
+ struct adv_monitor *monitor)
 {
struct msft_cp_le_monitor_advertisement *cp;
struct msft_le_monitor_advertisement_pattern_data *pattern_data;
@@ -387,9 +439,6 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct 
adv_monitor *monitor)
u8 pattern_count = 0;
int err = 0;
 
-   if (!msft)
-   return -EOPNOTSUPP;
-
if (!msft_monitor_pattern_valid(monitor))
return -EINVAL;
 
@@ -434,6 +483,20 @@ int msft_add_monitor_pattern(struct hci_dev

Re: [PATCH v5 0/5] MSFT offloading support for advertisement monitor

2021-01-12 Thread Archie Pusaka
Hi maintainers,

Gentle ping to review this patch, thanks~!

Regards,
Archie


On Tue, 22 Dec 2020 at 18:26, Archie Pusaka  wrote:
>
> From: Archie Pusaka 
>
>
> Hi linux-bluetooth,
>
> This series of patches manages the hardware offloading part of MSFT
> extension API. The full documentation can be accessed by this link:
> https://docs.microsoft.com/en-us/windows-hardware/drivers/bluetooth/microsoft-defined-bluetooth-hci-commands-and-events
>
> Only four of the HCI commands are planned to be implemented:
> HCI_VS_MSFT_Read_Supported_Features (implemented in previous patch),
> HCI_VS_MSFT_LE_Monitor_Advertisement,
> HCI_VS_MSFT_LE_Cancel_Monitor_Advertisement, and
> HCI_VS_MSFT_LE_Set_Advertisement_Filter_Enable.
> These are the commands which would be used for advertisement monitor
> feature. Only if the controller supports the MSFT extension would
> these commands be sent. Otherwise, software-based monitoring would be
> performed in the user space instead.
>
> Thanks in advance for your feedback!
>
> Archie
>
> Changes in v5:
> * Discard struct flags on msft_data and use it's members directly
>
> Changes in v4:
> * Change the logic of merging add_adv_patterns_monitor with rssi
> * Aligning variable declaration on mgmt.h
> * Replacing the usage of BT_DBG with bt_dev_dbg
>
> Changes in v3:
> * Flips the order of rssi and pattern_count on mgmt struct
> * Fix return type of msft_remove_monitor
>
> Changes in v2:
> * Add a new opcode instead of modifying an existing one
> * Also implement the new MGMT opcode and merge the functionality with
>   the old one.
>
> Archie Pusaka (5):
>   Bluetooth: advmon offload MSFT add rssi support
>   Bluetooth: advmon offload MSFT add monitor
>   Bluetooth: advmon offload MSFT remove monitor
>   Bluetooth: advmon offload MSFT handle controller reset
>   Bluetooth: advmon offload MSFT handle filter enablement
>
>  include/net/bluetooth/hci_core.h |  34 ++-
>  include/net/bluetooth/mgmt.h |  16 ++
>  net/bluetooth/hci_core.c | 174 +---
>  net/bluetooth/mgmt.c | 391 +++---
>  net/bluetooth/msft.c | 453 ++-
>  net/bluetooth/msft.h |  27 ++
>  6 files changed, 963 insertions(+), 132 deletions(-)
>
> --
> 2.29.2.729.g45daf8777d-goog
>


Re: [PATCH v3 4/5] Bluetooth: advmon offload MSFT handle controller reset

2020-12-22 Thread Archie Pusaka
Hi Marcel,

I've sent a new v5 patch to address this issue.

Thanks,
Archie

On Tue, 22 Dec 2020 at 18:03, Marcel Holtmann  wrote:
>
> Hi Archie,
>
> >>> When the controller is powered off, the registered advertising monitor
> >>> is removed from the controller. This patch handles the re-registration
> >>> of those monitors when the power is on.
> >>>
> >>> Signed-off-by: Archie Pusaka 
> >>> Reviewed-by: Miao-chen Chou 
> >>> Reviewed-by: Yun-Hao Chung 
> >>>
> >>> ---
> >>>
> >>> (no changes since v1)
> >>>
> >>> net/bluetooth/msft.c | 79 +---
> >>> 1 file changed, 74 insertions(+), 5 deletions(-)
> >>>
> >>> diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
> >>> index f5aa0e3b1b9b..7e33a85c3f1c 100644
> >>> --- a/net/bluetooth/msft.c
> >>> +++ b/net/bluetooth/msft.c
> >>> @@ -82,8 +82,15 @@ struct msft_data {
> >>>  struct list_head handle_map;
> >>>  __u16 pending_add_handle;
> >>>  __u16 pending_remove_handle;
> >>> +
> >>> + struct {
> >>> + u8 reregistering:1;
> >>> + } flags;
> >>> };
> >>
> >> hmmm. Do you have bigger plans with this struct? I would just skip it.
> >>
> > This struct is also used in patch 5/5 to store the "enabled" status of
> > the filter.
> > Suspend/resume would need to enable/disable the filter, but it is not
> > yet implemented in this patch series.
>
> just do it without the nested structs. I think you are overdoing it here.
>
> Regards
>
> Marcel
>


[PATCH v5 5/5] Bluetooth: advmon offload MSFT handle filter enablement

2020-12-22 Thread Archie Pusaka
From: Archie Pusaka 

Implements the feature to disable/enable the filter used for
advertising monitor on MSFT controller, effectively have the same
effect as "remove all monitors" and "add all previously removed
monitors".

This feature would be needed when suspending, where we would not want
to get packets from anything outside the allowlist. Note that the
integration with the suspending part is not included in this patch.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

(no changes since v1)

 net/bluetooth/msft.c | 67 
 net/bluetooth/msft.h |  6 
 2 files changed, 73 insertions(+)

diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index d25c6936daa4..b2ef654b1d3d 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -69,6 +69,17 @@ struct msft_rp_le_cancel_monitor_advertisement {
__u8 sub_opcode;
 } __packed;
 
+#define MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE 0x05
+struct msft_cp_le_set_advertisement_filter_enable {
+   __u8 sub_opcode;
+   __u8 enable;
+} __packed;
+
+struct msft_rp_le_set_advertisement_filter_enable {
+   __u8 status;
+   __u8 sub_opcode;
+} __packed;
+
 struct msft_monitor_advertisement_handle_data {
__u8  msft_handle;
__u16 mgmt_handle;
@@ -83,6 +94,7 @@ struct msft_data {
__u16 pending_add_handle;
__u16 pending_remove_handle;
__u8 reregistering;
+   __u8 filter_enabled;
 };
 
 static int __msft_add_monitor_pattern(struct hci_dev *hdev,
@@ -190,6 +202,7 @@ void msft_do_open(struct hci_dev *hdev)
 
if (msft_monitor_supported(hdev)) {
msft->reregistering = true;
+   msft_set_filter_enable(hdev, true);
reregister_monitor_on_restart(hdev, 0);
}
 }
@@ -395,6 +408,40 @@ static void msft_le_cancel_monitor_advertisement_cb(struct 
hci_dev *hdev,
hci_remove_adv_monitor_complete(hdev, status);
 }
 
+static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev,
+  u8 status, u16 opcode,
+  struct sk_buff *skb)
+{
+   struct msft_cp_le_set_advertisement_filter_enable *cp;
+   struct msft_rp_le_set_advertisement_filter_enable *rp;
+   struct msft_data *msft = hdev->msft_data;
+
+   rp = (struct msft_rp_le_set_advertisement_filter_enable *)skb->data;
+   if (skb->len < sizeof(*rp))
+   return;
+
+   /* Error 0x0C would be returned if the filter enabled status is
+* already set to whatever we were trying to set.
+* Although the default state should be disabled, some controller set
+* the initial value to enabled. Because there is no way to know the
+* actual initial value before sending this command, here we also treat
+* error 0x0C as success.
+*/
+   if (status != 0x00 && status != 0x0C)
+   return;
+
+   hci_dev_lock(hdev);
+
+   cp = hci_sent_cmd_data(hdev, hdev->msft_opcode);
+   msft->filter_enabled = cp->enable;
+
+   if (status == 0x0C)
+   bt_dev_warn(hdev, "MSFT filter_enable is already %s",
+   cp->enable ? "on" : "off");
+
+   hci_dev_unlock(hdev);
+}
+
 static bool msft_monitor_rssi_valid(struct adv_monitor *monitor)
 {
struct adv_rssi_thresholds *r = >rssi;
@@ -531,3 +578,23 @@ int msft_remove_monitor(struct hci_dev *hdev, struct 
adv_monitor *monitor,
 
return err;
 }
+
+int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
+{
+   struct msft_cp_le_set_advertisement_filter_enable cp;
+   struct hci_request req;
+   struct msft_data *msft = hdev->msft_data;
+   int err;
+
+   if (!msft)
+   return -EOPNOTSUPP;
+
+   cp.sub_opcode = MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE;
+   cp.enable = enable;
+
+   hci_req_init(, hdev);
+   hci_req_add(, hdev->msft_opcode, sizeof(cp), );
+   err = hci_req_run_skb(, msft_le_set_advertisement_filter_enable_cb);
+
+   return err;
+}
diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
index 6f126a1f1688..f8e4d3a6d641 100644
--- a/net/bluetooth/msft.h
+++ b/net/bluetooth/msft.h
@@ -20,6 +20,7 @@ __u64 msft_get_features(struct hci_dev *hdev);
 int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor 
*monitor);
 int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
u16 handle);
+int msft_set_filter_enable(struct hci_dev *hdev, bool enable);
 
 #else
 
@@ -45,4 +46,9 @@ static inline int msft_remove_monitor(struct hci_dev *hdev,
return -EOPNOTSUPP;
 }
 
+static inline int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
+{
+   return -EOPNOTSUPP;
+}
+
 #endif
-- 
2.29.2.729.g45daf8777d-goog



[PATCH v5 4/5] Bluetooth: advmon offload MSFT handle controller reset

2020-12-22 Thread Archie Pusaka
From: Archie Pusaka 

When the controller is powered off, the registered advertising monitor
is removed from the controller. This patch handles the re-registration
of those monitors when the power is on.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

Changes in v5:
* Discard struct flags on msft_data and use it's members directly

 net/bluetooth/msft.c | 76 +---
 1 file changed, 71 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index f5aa0e3b1b9b..d25c6936daa4 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -82,8 +82,12 @@ struct msft_data {
struct list_head handle_map;
__u16 pending_add_handle;
__u16 pending_remove_handle;
+   __u8 reregistering;
 };
 
+static int __msft_add_monitor_pattern(struct hci_dev *hdev,
+ struct adv_monitor *monitor);
+
 bool msft_monitor_supported(struct hci_dev *hdev)
 {
return !!(msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR);
@@ -134,6 +138,35 @@ static bool read_supported_features(struct hci_dev *hdev,
return false;
 }
 
+/* This function requires the caller holds hdev->lock */
+static void reregister_monitor_on_restart(struct hci_dev *hdev, int handle)
+{
+   struct adv_monitor *monitor;
+   struct msft_data *msft = hdev->msft_data;
+   int err;
+
+   while (1) {
+   monitor = idr_get_next(>adv_monitors_idr, );
+   if (!monitor) {
+   /* All monitors have been reregistered */
+   msft->reregistering = false;
+   hci_update_background_scan(hdev);
+   return;
+   }
+
+   msft->pending_add_handle = (u16)handle;
+   err = __msft_add_monitor_pattern(hdev, monitor);
+
+   /* If success, we return and wait for monitor added callback */
+   if (!err)
+   return;
+
+   /* Otherwise remove the monitor and keep registering */
+   hci_free_adv_monitor(hdev, monitor);
+   handle++;
+   }
+}
+
 void msft_do_open(struct hci_dev *hdev)
 {
struct msft_data *msft;
@@ -154,12 +187,18 @@ void msft_do_open(struct hci_dev *hdev)
 
INIT_LIST_HEAD(>handle_map);
hdev->msft_data = msft;
+
+   if (msft_monitor_supported(hdev)) {
+   msft->reregistering = true;
+   reregister_monitor_on_restart(hdev, 0);
+   }
 }
 
 void msft_do_close(struct hci_dev *hdev)
 {
struct msft_data *msft = hdev->msft_data;
struct msft_monitor_advertisement_handle_data *handle_data, *tmp;
+   struct adv_monitor *monitor;
 
if (!msft)
return;
@@ -169,6 +208,12 @@ void msft_do_close(struct hci_dev *hdev)
hdev->msft_data = NULL;
 
list_for_each_entry_safe(handle_data, tmp, >handle_map, list) {
+   monitor = idr_find(>adv_monitors_idr,
+  handle_data->mgmt_handle);
+
+   if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED)
+   monitor->state = ADV_MONITOR_STATE_REGISTERED;
+
list_del(_data->list);
kfree(handle_data);
}
@@ -282,9 +327,15 @@ static void msft_le_monitor_advertisement_cb(struct 
hci_dev *hdev,
if (status && monitor)
hci_free_adv_monitor(hdev, monitor);
 
+   /* If in restart/reregister sequence, keep registering. */
+   if (msft->reregistering)
+   reregister_monitor_on_restart(hdev,
+ msft->pending_add_handle + 1);
+
hci_dev_unlock(hdev);
 
-   hci_add_adv_patterns_monitor_complete(hdev, status);
+   if (!msft->reregistering)
+   hci_add_adv_patterns_monitor_complete(hdev, status);
 }
 
 static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
@@ -374,7 +425,8 @@ static bool msft_monitor_pattern_valid(struct adv_monitor 
*monitor)
 }
 
 /* This function requires the caller holds hdev->lock */
-int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor)
+static int __msft_add_monitor_pattern(struct hci_dev *hdev,
+ struct adv_monitor *monitor)
 {
struct msft_cp_le_monitor_advertisement *cp;
struct msft_le_monitor_advertisement_pattern_data *pattern_data;
@@ -387,9 +439,6 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct 
adv_monitor *monitor)
u8 pattern_count = 0;
int err = 0;
 
-   if (!msft)
-   return -EOPNOTSUPP;
-
if (!msft_monitor_pattern_valid(monitor))
return -EINVAL;
 
@@ -434,6 +483,20 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct 
adv_

[PATCH v5 2/5] Bluetooth: advmon offload MSFT add monitor

2020-12-22 Thread Archie Pusaka
From: Archie Pusaka 

Enables advertising monitor offloading to the controller, if MSFT
extension is supported. The kernel won't adjust the monitor parameters
to match what the controller supports - that is the user space's
responsibility.

This patch only manages the addition of monitors. Monitor removal is
going to be handled by another patch.

Signed-off-by: Archie Pusaka 
Reviewed-by: Manish Mandlik 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

(no changes since v4)

Changes in v4:
* Replacing the usage of BT_DBG with bt_dev_dbg

Changes in v2:
* Also implement the new MGMT opcode and merge the functionality with
  the old one.

 include/net/bluetooth/hci_core.h |  17 ++-
 net/bluetooth/hci_core.c |  55 +++--
 net/bluetooth/mgmt.c | 114 +-
 net/bluetooth/msft.c | 201 ++-
 net/bluetooth/msft.h |  12 ++
 5 files changed, 356 insertions(+), 43 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 8b7cf3620938..879d1e38ce96 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -261,13 +261,20 @@ struct adv_rssi_thresholds {
 struct adv_monitor {
struct list_head patterns;
struct adv_rssi_thresholds rssi;
-   boolactive;
__u16   handle;
+
+   enum {
+   ADV_MONITOR_STATE_NOT_REGISTERED,
+   ADV_MONITOR_STATE_REGISTERED,
+   ADV_MONITOR_STATE_OFFLOADED
+   } state;
 };
 
 #define HCI_MIN_ADV_MONITOR_HANDLE 1
-#define HCI_MAX_ADV_MONITOR_NUM_HANDLES32
+#define HCI_MAX_ADV_MONITOR_NUM_HANDLES32
 #define HCI_MAX_ADV_MONITOR_NUM_PATTERNS   16
+#define HCI_ADV_MONITOR_EXT_NONE   1
+#define HCI_ADV_MONITOR_EXT_MSFT   2
 
 #define HCI_MAX_SHORT_NAME_LENGTH  10
 
@@ -1326,9 +1333,12 @@ void hci_adv_instances_set_rpa_expired(struct hci_dev 
*hdev, bool rpa_expired);
 
 void hci_adv_monitors_clear(struct hci_dev *hdev);
 void hci_free_adv_monitor(struct adv_monitor *monitor);
-int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
+int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
+   int *err);
 int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle);
 bool hci_is_adv_monitoring(struct hci_dev *hdev);
+int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev);
 
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
 
@@ -1804,6 +1814,7 @@ void mgmt_advertising_added(struct sock *sk, struct 
hci_dev *hdev,
 void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
  u8 instance);
 int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
+int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
 
 u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
  u16 to_multiplier);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9d2c9a1c552f..625298f64a20 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3070,27 +3070,56 @@ void hci_free_adv_monitor(struct adv_monitor *monitor)
kfree(monitor);
 }
 
-/* This function requires the caller holds hdev->lock */
-int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
+int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)
+{
+   return mgmt_add_adv_patterns_monitor_complete(hdev, status);
+}
+
+/* Assigns handle to a monitor, and if offloading is supported and power is on,
+ * also attempts to forward the request to the controller.
+ * Returns true if request is forwarded (result is pending), false otherwise.
+ * This function requires the caller holds hdev->lock.
+ */
+bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
+int *err)
 {
int min, max, handle;
 
-   if (!monitor)
-   return -EINVAL;
+   *err = 0;
+
+   if (!monitor) {
+   *err = -EINVAL;
+   return false;
+   }
 
min = HCI_MIN_ADV_MONITOR_HANDLE;
max = HCI_MIN_ADV_MONITOR_HANDLE + HCI_MAX_ADV_MONITOR_NUM_HANDLES;
handle = idr_alloc(>adv_monitors_idr, monitor, min, max,
   GFP_KERNEL);
-   if (handle < 0)
-   return handle;
+   if (handle < 0) {
+   *err = handle;
+   return false;
+   }
 
-   hdev->adv_monitors_cnt++;
monitor->handle = handle;
 
-   hci_update_background_scan(hdev);
+   if (!hdev_is_powered(hdev))
+   return false;
 
-   return 0;
+   switch (hci_get_adv_monitor_offload_ext(hdev)) {
+   case HCI

[PATCH v5 3/5] Bluetooth: advmon offload MSFT remove monitor

2020-12-22 Thread Archie Pusaka
From: Archie Pusaka 

Implements the monitor removal functionality for advertising monitor
offloading to MSFT controllers. Supply handle = 0 to remove all
monitors.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 
Reported-by: kernel test robot 
Reported-by: Dan Carpenter 

---

(no changes since v3)

Changes in v3:
* Fix return type of msft_remove_monitor

 include/net/bluetooth/hci_core.h |   8 +-
 net/bluetooth/hci_core.c | 119 +++--
 net/bluetooth/mgmt.c | 110 +-
 net/bluetooth/msft.c | 127 ++-
 net/bluetooth/msft.h |   9 +++
 5 files changed, 323 insertions(+), 50 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 879d1e38ce96..29cfc6a2d689 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1332,11 +1332,13 @@ int hci_remove_adv_instance(struct hci_dev *hdev, u8 
instance);
 void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired);
 
 void hci_adv_monitors_clear(struct hci_dev *hdev);
-void hci_free_adv_monitor(struct adv_monitor *monitor);
+void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
 int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
 bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
int *err);
-int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle);
+bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err);
+bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err);
 bool hci_is_adv_monitoring(struct hci_dev *hdev);
 int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev);
 
@@ -1813,8 +1815,10 @@ void mgmt_advertising_added(struct sock *sk, struct 
hci_dev *hdev,
u8 instance);
 void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
  u8 instance);
+void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle);
 int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
 int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
 
 u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
  u16 to_multiplier);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 625298f64a20..b0a63f643a07 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3051,12 +3051,15 @@ void hci_adv_monitors_clear(struct hci_dev *hdev)
int handle;
 
idr_for_each_entry(>adv_monitors_idr, monitor, handle)
-   hci_free_adv_monitor(monitor);
+   hci_free_adv_monitor(hdev, monitor);
 
idr_destroy(>adv_monitors_idr);
 }
 
-void hci_free_adv_monitor(struct adv_monitor *monitor)
+/* Frees the monitor structure and do some bookkeepings.
+ * This function requires the caller holds hdev->lock.
+ */
+void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
 {
struct adv_pattern *pattern;
struct adv_pattern *tmp;
@@ -3064,8 +3067,18 @@ void hci_free_adv_monitor(struct adv_monitor *monitor)
if (!monitor)
return;
 
-   list_for_each_entry_safe(pattern, tmp, >patterns, list)
+   list_for_each_entry_safe(pattern, tmp, >patterns, list) {
+   list_del(>list);
kfree(pattern);
+   }
+
+   if (monitor->handle)
+   idr_remove(>adv_monitors_idr, monitor->handle);
+
+   if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED) {
+   hdev->adv_monitors_cnt--;
+   mgmt_adv_monitor_removed(hdev, monitor->handle);
+   }
 
kfree(monitor);
 }
@@ -3075,6 +3088,11 @@ int hci_add_adv_patterns_monitor_complete(struct hci_dev 
*hdev, u8 status)
return mgmt_add_adv_patterns_monitor_complete(hdev, status);
 }
 
+int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
+{
+   return mgmt_remove_adv_monitor_complete(hdev, status);
+}
+
 /* Assigns handle to a monitor, and if offloading is supported and power is on,
  * also attempts to forward the request to the controller.
  * Returns true if request is forwarded (result is pending), false otherwise.
@@ -3122,39 +3140,94 @@ bool hci_add_adv_monitor(struct hci_dev *hdev, struct 
adv_monitor *monitor,
return (*err == 0);
 }
 
-static int free_adv_monitor(int id, void *ptr, void *data)
+/* Attempts to tell the controller and free the monitor. If somehow the
+ * controller doesn't have a corresponding handle, remove anyway.
+ * Returns true if request is forwarded (result is pending), false otherwise.
+ * This function 

[PATCH v5 0/5] MSFT offloading support for advertisement monitor

2020-12-22 Thread Archie Pusaka
From: Archie Pusaka 


Hi linux-bluetooth,

This series of patches manages the hardware offloading part of MSFT
extension API. The full documentation can be accessed by this link:
https://docs.microsoft.com/en-us/windows-hardware/drivers/bluetooth/microsoft-defined-bluetooth-hci-commands-and-events

Only four of the HCI commands are planned to be implemented:
HCI_VS_MSFT_Read_Supported_Features (implemented in previous patch),
HCI_VS_MSFT_LE_Monitor_Advertisement,
HCI_VS_MSFT_LE_Cancel_Monitor_Advertisement, and
HCI_VS_MSFT_LE_Set_Advertisement_Filter_Enable.
These are the commands which would be used for advertisement monitor
feature. Only if the controller supports the MSFT extension would
these commands be sent. Otherwise, software-based monitoring would be
performed in the user space instead.

Thanks in advance for your feedback!

Archie

Changes in v5:
* Discard struct flags on msft_data and use it's members directly

Changes in v4:
* Change the logic of merging add_adv_patterns_monitor with rssi
* Aligning variable declaration on mgmt.h
* Replacing the usage of BT_DBG with bt_dev_dbg

Changes in v3:
* Flips the order of rssi and pattern_count on mgmt struct
* Fix return type of msft_remove_monitor

Changes in v2:
* Add a new opcode instead of modifying an existing one
* Also implement the new MGMT opcode and merge the functionality with
  the old one.

Archie Pusaka (5):
  Bluetooth: advmon offload MSFT add rssi support
  Bluetooth: advmon offload MSFT add monitor
  Bluetooth: advmon offload MSFT remove monitor
  Bluetooth: advmon offload MSFT handle controller reset
  Bluetooth: advmon offload MSFT handle filter enablement

 include/net/bluetooth/hci_core.h |  34 ++-
 include/net/bluetooth/mgmt.h |  16 ++
 net/bluetooth/hci_core.c | 174 +---
 net/bluetooth/mgmt.c | 391 +++---
 net/bluetooth/msft.c | 453 ++-
 net/bluetooth/msft.h |  27 ++
 6 files changed, 963 insertions(+), 132 deletions(-)

-- 
2.29.2.729.g45daf8777d-goog



[PATCH v5 1/5] Bluetooth: advmon offload MSFT add rssi support

2020-12-22 Thread Archie Pusaka
From: Archie Pusaka 

MSFT needs rssi parameter for monitoring advertisement packet,
therefore we should supply them from mgmt. This adds a new opcode
to add advertisement monitor with rssi parameters.

Signed-off-by: Archie Pusaka 
Reviewed-by: Manish Mandlik 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

(no changes since v4)

Changes in v4:
* Change the logic of merging add_adv_patterns_monitor with rssi
* Aligning variable declaration on mgmt.h

Changes in v3:
* Flips the order of rssi and pattern_count on mgmt struct

Changes in v2:
* Add a new opcode instead of modifying an existing one

 include/net/bluetooth/hci_core.h |   9 ++
 include/net/bluetooth/mgmt.h |  16 +++
 net/bluetooth/mgmt.c | 225 +--
 3 files changed, 178 insertions(+), 72 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 677a8c50b2ad..8b7cf3620938 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -250,8 +250,17 @@ struct adv_pattern {
__u8 value[HCI_MAX_AD_LENGTH];
 };
 
+struct adv_rssi_thresholds {
+   __s8 low_threshold;
+   __s8 high_threshold;
+   __u16 low_threshold_timeout;
+   __u16 high_threshold_timeout;
+   __u8 sampling_period;
+};
+
 struct adv_monitor {
struct list_head patterns;
+   struct adv_rssi_thresholds rssi;
boolactive;
__u16   handle;
 };
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index f9a6638e20b3..839a2028009e 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -821,6 +821,22 @@ struct mgmt_rp_add_ext_adv_data {
__u8instance;
 } __packed;
 
+struct mgmt_adv_rssi_thresholds {
+   __s8high_threshold;
+   __le16  high_threshold_timeout;
+   __s8low_threshold;
+   __le16  low_threshold_timeout;
+   __u8sampling_period;
+} __packed;
+
+#define MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI  0x0056
+struct mgmt_cp_add_adv_patterns_monitor_rssi {
+   struct mgmt_adv_rssi_thresholds rssi;
+   __u8pattern_count;
+   struct mgmt_adv_pattern patterns[];
+} __packed;
+#define MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE8
+
 #define MGMT_EV_CMD_COMPLETE   0x0001
 struct mgmt_ev_cmd_complete {
__le16  opcode;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 608dda5403b7..72d37c80e071 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -124,6 +124,7 @@ static const u16 mgmt_commands[] = {
MGMT_OP_REMOVE_ADV_MONITOR,
MGMT_OP_ADD_EXT_ADV_PARAMS,
MGMT_OP_ADD_EXT_ADV_DATA,
+   MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI,
 };
 
 static const u16 mgmt_events[] = {
@@ -4225,75 +4226,15 @@ static int read_adv_mon_features(struct sock *sk, 
struct hci_dev *hdev,
return err;
 }
 
-static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
-   void *data, u16 len)
+static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
+ struct adv_monitor *m, u8 status, u16 op)
 {
-   struct mgmt_cp_add_adv_patterns_monitor *cp = data;
struct mgmt_rp_add_adv_patterns_monitor rp;
-   struct adv_monitor *m = NULL;
-   struct adv_pattern *p = NULL;
-   unsigned int mp_cnt = 0, prev_adv_monitors_cnt;
-   __u8 cp_ofst = 0, cp_len = 0;
-   int err, i;
-
-   BT_DBG("request for %s", hdev->name);
-
-   if (len <= sizeof(*cp) || cp->pattern_count == 0) {
-   err = mgmt_cmd_status(sk, hdev->id,
- MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
- MGMT_STATUS_INVALID_PARAMS);
-   goto failed;
-   }
-
-   m = kmalloc(sizeof(*m), GFP_KERNEL);
-   if (!m) {
-   err = -ENOMEM;
-   goto failed;
-   }
-
-   INIT_LIST_HEAD(>patterns);
-   m->active = false;
-
-   for (i = 0; i < cp->pattern_count; i++) {
-   if (++mp_cnt > HCI_MAX_ADV_MONITOR_NUM_PATTERNS) {
-   err = mgmt_cmd_status(sk, hdev->id,
- MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
- MGMT_STATUS_INVALID_PARAMS);
-   goto failed;
-   }
-
-   cp_ofst = cp->patterns[i].offset;
-   cp_len = cp->patterns[i].length;
-   if (cp_ofst >= HCI_MAX_AD_LENGTH ||
-   cp_len > HCI_MAX_AD_LENGTH ||
-   (cp_ofst + cp_len) > HCI_MAX_AD_LENGTH) {
-   err = mgmt_cmd_status(sk, hdev->id,
- MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
- MGMT_STATUS_INVALID_PARAMS);
-   go

[PATCH v4 5/5] Bluetooth: advmon offload MSFT handle filter enablement

2020-12-22 Thread Archie Pusaka
From: Archie Pusaka 

Implements the feature to disable/enable the filter used for
advertising monitor on MSFT controller, effectively have the same
effect as "remove all monitors" and "add all previously removed
monitors".

This feature would be needed when suspending, where we would not want
to get packets from anything outside the allowlist. Note that the
integration with the suspending part is not included in this patch.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

(no changes since v1)

 net/bluetooth/msft.c | 67 
 net/bluetooth/msft.h |  6 
 2 files changed, 73 insertions(+)

diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index 7e33a85c3f1c..055cc5a260df 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -69,6 +69,17 @@ struct msft_rp_le_cancel_monitor_advertisement {
__u8 sub_opcode;
 } __packed;
 
+#define MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE 0x05
+struct msft_cp_le_set_advertisement_filter_enable {
+   __u8 sub_opcode;
+   __u8 enable;
+} __packed;
+
+struct msft_rp_le_set_advertisement_filter_enable {
+   __u8 status;
+   __u8 sub_opcode;
+} __packed;
+
 struct msft_monitor_advertisement_handle_data {
__u8  msft_handle;
__u16 mgmt_handle;
@@ -85,6 +96,7 @@ struct msft_data {
 
struct {
u8 reregistering:1;
+   u8 filter_enabled:1;
} flags;
 };
 
@@ -193,6 +205,7 @@ void msft_do_open(struct hci_dev *hdev)
 
if (msft_monitor_supported(hdev)) {
msft->flags.reregistering = true;
+   msft_set_filter_enable(hdev, true);
reregister_monitor_on_restart(hdev, 0);
}
 }
@@ -398,6 +411,40 @@ static void msft_le_cancel_monitor_advertisement_cb(struct 
hci_dev *hdev,
hci_remove_adv_monitor_complete(hdev, status);
 }
 
+static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev,
+  u8 status, u16 opcode,
+  struct sk_buff *skb)
+{
+   struct msft_cp_le_set_advertisement_filter_enable *cp;
+   struct msft_rp_le_set_advertisement_filter_enable *rp;
+   struct msft_data *msft = hdev->msft_data;
+
+   rp = (struct msft_rp_le_set_advertisement_filter_enable *)skb->data;
+   if (skb->len < sizeof(*rp))
+   return;
+
+   /* Error 0x0C would be returned if the filter enabled status is
+* already set to whatever we were trying to set.
+* Although the default state should be disabled, some controller set
+* the initial value to enabled. Because there is no way to know the
+* actual initial value before sending this command, here we also treat
+* error 0x0C as success.
+*/
+   if (status != 0x00 && status != 0x0C)
+   return;
+
+   hci_dev_lock(hdev);
+
+   cp = hci_sent_cmd_data(hdev, hdev->msft_opcode);
+   msft->flags.filter_enabled = cp->enable;
+
+   if (status == 0x0C)
+   bt_dev_warn(hdev, "MSFT filter_enable is already %s",
+   cp->enable ? "on" : "off");
+
+   hci_dev_unlock(hdev);
+}
+
 static bool msft_monitor_rssi_valid(struct adv_monitor *monitor)
 {
struct adv_rssi_thresholds *r = >rssi;
@@ -534,3 +581,23 @@ int msft_remove_monitor(struct hci_dev *hdev, struct 
adv_monitor *monitor,
 
return err;
 }
+
+int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
+{
+   struct msft_cp_le_set_advertisement_filter_enable cp;
+   struct hci_request req;
+   struct msft_data *msft = hdev->msft_data;
+   int err;
+
+   if (!msft)
+   return -EOPNOTSUPP;
+
+   cp.sub_opcode = MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE;
+   cp.enable = enable;
+
+   hci_req_init(, hdev);
+   hci_req_add(, hdev->msft_opcode, sizeof(cp), );
+   err = hci_req_run_skb(, msft_le_set_advertisement_filter_enable_cb);
+
+   return err;
+}
diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
index 6f126a1f1688..f8e4d3a6d641 100644
--- a/net/bluetooth/msft.h
+++ b/net/bluetooth/msft.h
@@ -20,6 +20,7 @@ __u64 msft_get_features(struct hci_dev *hdev);
 int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor 
*monitor);
 int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
u16 handle);
+int msft_set_filter_enable(struct hci_dev *hdev, bool enable);
 
 #else
 
@@ -45,4 +46,9 @@ static inline int msft_remove_monitor(struct hci_dev *hdev,
return -EOPNOTSUPP;
 }
 
+static inline int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
+{
+   return -EOPNOTSUPP;
+}
+
 #endif
-- 
2.29.2.729.g45daf8777d-goog



[PATCH v4 4/5] Bluetooth: advmon offload MSFT handle controller reset

2020-12-22 Thread Archie Pusaka
From: Archie Pusaka 

When the controller is powered off, the registered advertising monitor
is removed from the controller. This patch handles the re-registration
of those monitors when the power is on.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

(no changes since v1)

 net/bluetooth/msft.c | 79 +---
 1 file changed, 74 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index f5aa0e3b1b9b..7e33a85c3f1c 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -82,8 +82,15 @@ struct msft_data {
struct list_head handle_map;
__u16 pending_add_handle;
__u16 pending_remove_handle;
+
+   struct {
+   u8 reregistering:1;
+   } flags;
 };
 
+static int __msft_add_monitor_pattern(struct hci_dev *hdev,
+ struct adv_monitor *monitor);
+
 bool msft_monitor_supported(struct hci_dev *hdev)
 {
return !!(msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR);
@@ -134,6 +141,35 @@ static bool read_supported_features(struct hci_dev *hdev,
return false;
 }
 
+/* This function requires the caller holds hdev->lock */
+static void reregister_monitor_on_restart(struct hci_dev *hdev, int handle)
+{
+   struct adv_monitor *monitor;
+   struct msft_data *msft = hdev->msft_data;
+   int err;
+
+   while (1) {
+   monitor = idr_get_next(>adv_monitors_idr, );
+   if (!monitor) {
+   /* All monitors have been reregistered */
+   msft->flags.reregistering = false;
+   hci_update_background_scan(hdev);
+   return;
+   }
+
+   msft->pending_add_handle = (u16)handle;
+   err = __msft_add_monitor_pattern(hdev, monitor);
+
+   /* If success, we return and wait for monitor added callback */
+   if (!err)
+   return;
+
+   /* Otherwise remove the monitor and keep registering */
+   hci_free_adv_monitor(hdev, monitor);
+   handle++;
+   }
+}
+
 void msft_do_open(struct hci_dev *hdev)
 {
struct msft_data *msft;
@@ -154,12 +190,18 @@ void msft_do_open(struct hci_dev *hdev)
 
INIT_LIST_HEAD(>handle_map);
hdev->msft_data = msft;
+
+   if (msft_monitor_supported(hdev)) {
+   msft->flags.reregistering = true;
+   reregister_monitor_on_restart(hdev, 0);
+   }
 }
 
 void msft_do_close(struct hci_dev *hdev)
 {
struct msft_data *msft = hdev->msft_data;
struct msft_monitor_advertisement_handle_data *handle_data, *tmp;
+   struct adv_monitor *monitor;
 
if (!msft)
return;
@@ -169,6 +211,12 @@ void msft_do_close(struct hci_dev *hdev)
hdev->msft_data = NULL;
 
list_for_each_entry_safe(handle_data, tmp, >handle_map, list) {
+   monitor = idr_find(>adv_monitors_idr,
+  handle_data->mgmt_handle);
+
+   if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED)
+   monitor->state = ADV_MONITOR_STATE_REGISTERED;
+
list_del(_data->list);
kfree(handle_data);
}
@@ -282,9 +330,15 @@ static void msft_le_monitor_advertisement_cb(struct 
hci_dev *hdev,
if (status && monitor)
hci_free_adv_monitor(hdev, monitor);
 
+   /* If in restart/reregister sequence, keep registering. */
+   if (msft->flags.reregistering)
+   reregister_monitor_on_restart(hdev,
+ msft->pending_add_handle + 1);
+
hci_dev_unlock(hdev);
 
-   hci_add_adv_patterns_monitor_complete(hdev, status);
+   if (!msft->flags.reregistering)
+   hci_add_adv_patterns_monitor_complete(hdev, status);
 }
 
 static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
@@ -374,7 +428,8 @@ static bool msft_monitor_pattern_valid(struct adv_monitor 
*monitor)
 }
 
 /* This function requires the caller holds hdev->lock */
-int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor)
+static int __msft_add_monitor_pattern(struct hci_dev *hdev,
+ struct adv_monitor *monitor)
 {
struct msft_cp_le_monitor_advertisement *cp;
struct msft_le_monitor_advertisement_pattern_data *pattern_data;
@@ -387,9 +442,6 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct 
adv_monitor *monitor)
u8 pattern_count = 0;
int err = 0;
 
-   if (!msft)
-   return -EOPNOTSUPP;
-
if (!msft_monitor_pattern_valid(monitor))
return -EINVAL;
 
@@ -434,6 +486,20 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, s

[PATCH v4 3/5] Bluetooth: advmon offload MSFT remove monitor

2020-12-22 Thread Archie Pusaka
From: Archie Pusaka 

Implements the monitor removal functionality for advertising monitor
offloading to MSFT controllers. Supply handle = 0 to remove all
monitors.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 
Reported-by: kernel test robot 
Reported-by: Dan Carpenter 

---

(no changes since v3)

Changes in v3:
* Fix return type of msft_remove_monitor

 include/net/bluetooth/hci_core.h |   8 +-
 net/bluetooth/hci_core.c | 119 +++--
 net/bluetooth/mgmt.c | 110 +-
 net/bluetooth/msft.c | 127 ++-
 net/bluetooth/msft.h |   9 +++
 5 files changed, 323 insertions(+), 50 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 879d1e38ce96..29cfc6a2d689 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1332,11 +1332,13 @@ int hci_remove_adv_instance(struct hci_dev *hdev, u8 
instance);
 void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired);
 
 void hci_adv_monitors_clear(struct hci_dev *hdev);
-void hci_free_adv_monitor(struct adv_monitor *monitor);
+void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
 int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
 bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
int *err);
-int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle);
+bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err);
+bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err);
 bool hci_is_adv_monitoring(struct hci_dev *hdev);
 int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev);
 
@@ -1813,8 +1815,10 @@ void mgmt_advertising_added(struct sock *sk, struct 
hci_dev *hdev,
u8 instance);
 void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
  u8 instance);
+void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle);
 int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
 int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
 
 u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
  u16 to_multiplier);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 625298f64a20..b0a63f643a07 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3051,12 +3051,15 @@ void hci_adv_monitors_clear(struct hci_dev *hdev)
int handle;
 
idr_for_each_entry(>adv_monitors_idr, monitor, handle)
-   hci_free_adv_monitor(monitor);
+   hci_free_adv_monitor(hdev, monitor);
 
idr_destroy(>adv_monitors_idr);
 }
 
-void hci_free_adv_monitor(struct adv_monitor *monitor)
+/* Frees the monitor structure and do some bookkeepings.
+ * This function requires the caller holds hdev->lock.
+ */
+void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
 {
struct adv_pattern *pattern;
struct adv_pattern *tmp;
@@ -3064,8 +3067,18 @@ void hci_free_adv_monitor(struct adv_monitor *monitor)
if (!monitor)
return;
 
-   list_for_each_entry_safe(pattern, tmp, >patterns, list)
+   list_for_each_entry_safe(pattern, tmp, >patterns, list) {
+   list_del(>list);
kfree(pattern);
+   }
+
+   if (monitor->handle)
+   idr_remove(>adv_monitors_idr, monitor->handle);
+
+   if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED) {
+   hdev->adv_monitors_cnt--;
+   mgmt_adv_monitor_removed(hdev, monitor->handle);
+   }
 
kfree(monitor);
 }
@@ -3075,6 +3088,11 @@ int hci_add_adv_patterns_monitor_complete(struct hci_dev 
*hdev, u8 status)
return mgmt_add_adv_patterns_monitor_complete(hdev, status);
 }
 
+int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
+{
+   return mgmt_remove_adv_monitor_complete(hdev, status);
+}
+
 /* Assigns handle to a monitor, and if offloading is supported and power is on,
  * also attempts to forward the request to the controller.
  * Returns true if request is forwarded (result is pending), false otherwise.
@@ -3122,39 +3140,94 @@ bool hci_add_adv_monitor(struct hci_dev *hdev, struct 
adv_monitor *monitor,
return (*err == 0);
 }
 
-static int free_adv_monitor(int id, void *ptr, void *data)
+/* Attempts to tell the controller and free the monitor. If somehow the
+ * controller doesn't have a corresponding handle, remove anyway.
+ * Returns true if request is forwarded (result is pending), false otherwise.
+ * This function 

[PATCH v4 1/5] Bluetooth: advmon offload MSFT add rssi support

2020-12-22 Thread Archie Pusaka
From: Archie Pusaka 

MSFT needs rssi parameter for monitoring advertisement packet,
therefore we should supply them from mgmt. This adds a new opcode
to add advertisement monitor with rssi parameters.

Signed-off-by: Archie Pusaka 
Reviewed-by: Manish Mandlik 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

Changes in v4:
* Change the logic of merging add_adv_patterns_monitor with rssi
* Aligning variable declaration on mgmt.h

Changes in v3:
* Flips the order of rssi and pattern_count on mgmt struct

Changes in v2:
* Add a new opcode instead of modifying an existing one

 include/net/bluetooth/hci_core.h |   9 ++
 include/net/bluetooth/mgmt.h |  16 +++
 net/bluetooth/mgmt.c | 225 +--
 3 files changed, 178 insertions(+), 72 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 677a8c50b2ad..8b7cf3620938 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -250,8 +250,17 @@ struct adv_pattern {
__u8 value[HCI_MAX_AD_LENGTH];
 };
 
+struct adv_rssi_thresholds {
+   __s8 low_threshold;
+   __s8 high_threshold;
+   __u16 low_threshold_timeout;
+   __u16 high_threshold_timeout;
+   __u8 sampling_period;
+};
+
 struct adv_monitor {
struct list_head patterns;
+   struct adv_rssi_thresholds rssi;
boolactive;
__u16   handle;
 };
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index f9a6638e20b3..839a2028009e 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -821,6 +821,22 @@ struct mgmt_rp_add_ext_adv_data {
__u8instance;
 } __packed;
 
+struct mgmt_adv_rssi_thresholds {
+   __s8high_threshold;
+   __le16  high_threshold_timeout;
+   __s8low_threshold;
+   __le16  low_threshold_timeout;
+   __u8sampling_period;
+} __packed;
+
+#define MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI  0x0056
+struct mgmt_cp_add_adv_patterns_monitor_rssi {
+   struct mgmt_adv_rssi_thresholds rssi;
+   __u8pattern_count;
+   struct mgmt_adv_pattern patterns[];
+} __packed;
+#define MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE8
+
 #define MGMT_EV_CMD_COMPLETE   0x0001
 struct mgmt_ev_cmd_complete {
__le16  opcode;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 608dda5403b7..72d37c80e071 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -124,6 +124,7 @@ static const u16 mgmt_commands[] = {
MGMT_OP_REMOVE_ADV_MONITOR,
MGMT_OP_ADD_EXT_ADV_PARAMS,
MGMT_OP_ADD_EXT_ADV_DATA,
+   MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI,
 };
 
 static const u16 mgmt_events[] = {
@@ -4225,75 +4226,15 @@ static int read_adv_mon_features(struct sock *sk, 
struct hci_dev *hdev,
return err;
 }
 
-static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
-   void *data, u16 len)
+static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
+ struct adv_monitor *m, u8 status, u16 op)
 {
-   struct mgmt_cp_add_adv_patterns_monitor *cp = data;
struct mgmt_rp_add_adv_patterns_monitor rp;
-   struct adv_monitor *m = NULL;
-   struct adv_pattern *p = NULL;
-   unsigned int mp_cnt = 0, prev_adv_monitors_cnt;
-   __u8 cp_ofst = 0, cp_len = 0;
-   int err, i;
-
-   BT_DBG("request for %s", hdev->name);
-
-   if (len <= sizeof(*cp) || cp->pattern_count == 0) {
-   err = mgmt_cmd_status(sk, hdev->id,
- MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
- MGMT_STATUS_INVALID_PARAMS);
-   goto failed;
-   }
-
-   m = kmalloc(sizeof(*m), GFP_KERNEL);
-   if (!m) {
-   err = -ENOMEM;
-   goto failed;
-   }
-
-   INIT_LIST_HEAD(>patterns);
-   m->active = false;
-
-   for (i = 0; i < cp->pattern_count; i++) {
-   if (++mp_cnt > HCI_MAX_ADV_MONITOR_NUM_PATTERNS) {
-   err = mgmt_cmd_status(sk, hdev->id,
- MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
- MGMT_STATUS_INVALID_PARAMS);
-   goto failed;
-   }
-
-   cp_ofst = cp->patterns[i].offset;
-   cp_len = cp->patterns[i].length;
-   if (cp_ofst >= HCI_MAX_AD_LENGTH ||
-   cp_len > HCI_MAX_AD_LENGTH ||
-   (cp_ofst + cp_len) > HCI_MAX_AD_LENGTH) {
-   err = mgmt_cmd_status(sk, hdev->id,
- MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
- MGMT_STATUS_INVALID_PARAMS);
-   goto failed;
-   

[PATCH v4 2/5] Bluetooth: advmon offload MSFT add monitor

2020-12-22 Thread Archie Pusaka
From: Archie Pusaka 

Enables advertising monitor offloading to the controller, if MSFT
extension is supported. The kernel won't adjust the monitor parameters
to match what the controller supports - that is the user space's
responsibility.

This patch only manages the addition of monitors. Monitor removal is
going to be handled by another patch.

Signed-off-by: Archie Pusaka 
Reviewed-by: Manish Mandlik 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

Changes in v4:
* Replacing the usage of BT_DBG with bt_dev_dbg

Changes in v2:
* Also implement the new MGMT opcode and merge the functionality with
  the old one.

 include/net/bluetooth/hci_core.h |  17 ++-
 net/bluetooth/hci_core.c |  55 +++--
 net/bluetooth/mgmt.c | 114 +-
 net/bluetooth/msft.c | 201 ++-
 net/bluetooth/msft.h |  12 ++
 5 files changed, 356 insertions(+), 43 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 8b7cf3620938..879d1e38ce96 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -261,13 +261,20 @@ struct adv_rssi_thresholds {
 struct adv_monitor {
struct list_head patterns;
struct adv_rssi_thresholds rssi;
-   boolactive;
__u16   handle;
+
+   enum {
+   ADV_MONITOR_STATE_NOT_REGISTERED,
+   ADV_MONITOR_STATE_REGISTERED,
+   ADV_MONITOR_STATE_OFFLOADED
+   } state;
 };
 
 #define HCI_MIN_ADV_MONITOR_HANDLE 1
-#define HCI_MAX_ADV_MONITOR_NUM_HANDLES32
+#define HCI_MAX_ADV_MONITOR_NUM_HANDLES32
 #define HCI_MAX_ADV_MONITOR_NUM_PATTERNS   16
+#define HCI_ADV_MONITOR_EXT_NONE   1
+#define HCI_ADV_MONITOR_EXT_MSFT   2
 
 #define HCI_MAX_SHORT_NAME_LENGTH  10
 
@@ -1326,9 +1333,12 @@ void hci_adv_instances_set_rpa_expired(struct hci_dev 
*hdev, bool rpa_expired);
 
 void hci_adv_monitors_clear(struct hci_dev *hdev);
 void hci_free_adv_monitor(struct adv_monitor *monitor);
-int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
+int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
+   int *err);
 int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle);
 bool hci_is_adv_monitoring(struct hci_dev *hdev);
+int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev);
 
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
 
@@ -1804,6 +1814,7 @@ void mgmt_advertising_added(struct sock *sk, struct 
hci_dev *hdev,
 void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
  u8 instance);
 int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
+int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
 
 u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
  u16 to_multiplier);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9d2c9a1c552f..625298f64a20 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3070,27 +3070,56 @@ void hci_free_adv_monitor(struct adv_monitor *monitor)
kfree(monitor);
 }
 
-/* This function requires the caller holds hdev->lock */
-int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
+int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)
+{
+   return mgmt_add_adv_patterns_monitor_complete(hdev, status);
+}
+
+/* Assigns handle to a monitor, and if offloading is supported and power is on,
+ * also attempts to forward the request to the controller.
+ * Returns true if request is forwarded (result is pending), false otherwise.
+ * This function requires the caller holds hdev->lock.
+ */
+bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
+int *err)
 {
int min, max, handle;
 
-   if (!monitor)
-   return -EINVAL;
+   *err = 0;
+
+   if (!monitor) {
+   *err = -EINVAL;
+   return false;
+   }
 
min = HCI_MIN_ADV_MONITOR_HANDLE;
max = HCI_MIN_ADV_MONITOR_HANDLE + HCI_MAX_ADV_MONITOR_NUM_HANDLES;
handle = idr_alloc(>adv_monitors_idr, monitor, min, max,
   GFP_KERNEL);
-   if (handle < 0)
-   return handle;
+   if (handle < 0) {
+   *err = handle;
+   return false;
+   }
 
-   hdev->adv_monitors_cnt++;
monitor->handle = handle;
 
-   hci_update_background_scan(hdev);
+   if (!hdev_is_powered(hdev))
+   return false;
 
-   return 0;
+   switch (hci_get_adv_monitor_offload_ext(hdev)) {
+   case HCI_ADV_MONITOR_EXT_NONE:
+   hci_update

[PATCH v4 0/5] MSFT offloading support for advertisement monitor

2020-12-22 Thread Archie Pusaka
From: Archie Pusaka 


Hi linux-bluetooth,

This series of patches manages the hardware offloading part of MSFT
extension API. The full documentation can be accessed by this link:
https://docs.microsoft.com/en-us/windows-hardware/drivers/bluetooth/microsoft-defined-bluetooth-hci-commands-and-events

Only four of the HCI commands are planned to be implemented:
HCI_VS_MSFT_Read_Supported_Features (implemented in previous patch),
HCI_VS_MSFT_LE_Monitor_Advertisement,
HCI_VS_MSFT_LE_Cancel_Monitor_Advertisement, and
HCI_VS_MSFT_LE_Set_Advertisement_Filter_Enable.
These are the commands which would be used for advertisement monitor
feature. Only if the controller supports the MSFT extension would
these commands be sent. Otherwise, software-based monitoring would be
performed in the user space instead.

Thanks in advance for your feedback!

Archie

Changes in v4:
* Change the logic of merging add_adv_patterns_monitor with rssi
* Aligning variable declaration on mgmt.h
* Replacing the usage of BT_DBG with bt_dev_dbg

Changes in v3:
* Flips the order of rssi and pattern_count on mgmt struct
* Fix return type of msft_remove_monitor

Changes in v2:
* Add a new opcode instead of modifying an existing one
* Also implement the new MGMT opcode and merge the functionality with
  the old one.

Archie Pusaka (5):
  Bluetooth: advmon offload MSFT add rssi support
  Bluetooth: advmon offload MSFT add monitor
  Bluetooth: advmon offload MSFT remove monitor
  Bluetooth: advmon offload MSFT handle controller reset
  Bluetooth: advmon offload MSFT handle filter enablement

 include/net/bluetooth/hci_core.h |  34 ++-
 include/net/bluetooth/mgmt.h |  16 ++
 net/bluetooth/hci_core.c | 174 +---
 net/bluetooth/mgmt.c | 391 +++---
 net/bluetooth/msft.c | 456 ++-
 net/bluetooth/msft.h |  27 ++
 6 files changed, 966 insertions(+), 132 deletions(-)

-- 
2.29.2.729.g45daf8777d-goog



Re: [PATCH v3 4/5] Bluetooth: advmon offload MSFT handle controller reset

2020-12-21 Thread Archie Pusaka
Hi Marcel,

On Mon, 21 Dec 2020 at 17:12, Marcel Holtmann  wrote:
>
> Hi Archie,
>
> > When the controller is powered off, the registered advertising monitor
> > is removed from the controller. This patch handles the re-registration
> > of those monitors when the power is on.
> >
> > Signed-off-by: Archie Pusaka 
> > Reviewed-by: Miao-chen Chou 
> > Reviewed-by: Yun-Hao Chung 
> >
> > ---
> >
> > (no changes since v1)
> >
> > net/bluetooth/msft.c | 79 +---
> > 1 file changed, 74 insertions(+), 5 deletions(-)
> >
> > diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
> > index f5aa0e3b1b9b..7e33a85c3f1c 100644
> > --- a/net/bluetooth/msft.c
> > +++ b/net/bluetooth/msft.c
> > @@ -82,8 +82,15 @@ struct msft_data {
> >   struct list_head handle_map;
> >   __u16 pending_add_handle;
> >   __u16 pending_remove_handle;
> > +
> > + struct {
> > + u8 reregistering:1;
> > + } flags;
> > };
>
> hmmm. Do you have bigger plans with this struct? I would just skip it.
>
This struct is also used in patch 5/5 to store the "enabled" status of
the filter.
Suspend/resume would need to enable/disable the filter, but it is not
yet implemented in this patch series.

Thanks,
Archie


[PATCH v3 3/5] Bluetooth: advmon offload MSFT remove monitor

2020-12-15 Thread Archie Pusaka
From: Archie Pusaka 

Implements the monitor removal functionality for advertising monitor
offloading to MSFT controllers. Supply handle = 0 to remove all
monitors.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 
Reported-by: kernel test robot 
Reported-by: Dan Carpenter 

---

Changes in v3:
* Fix return type of msft_remove_monitor

 include/net/bluetooth/hci_core.h |   8 +-
 net/bluetooth/hci_core.c | 119 +++--
 net/bluetooth/mgmt.c | 110 +-
 net/bluetooth/msft.c | 127 ++-
 net/bluetooth/msft.h |   9 +++
 5 files changed, 323 insertions(+), 50 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 879d1e38ce96..29cfc6a2d689 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1332,11 +1332,13 @@ int hci_remove_adv_instance(struct hci_dev *hdev, u8 
instance);
 void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired);
 
 void hci_adv_monitors_clear(struct hci_dev *hdev);
-void hci_free_adv_monitor(struct adv_monitor *monitor);
+void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
 int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
 bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
int *err);
-int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle);
+bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err);
+bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err);
 bool hci_is_adv_monitoring(struct hci_dev *hdev);
 int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev);
 
@@ -1813,8 +1815,10 @@ void mgmt_advertising_added(struct sock *sk, struct 
hci_dev *hdev,
u8 instance);
 void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
  u8 instance);
+void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle);
 int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
 int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
 
 u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
  u16 to_multiplier);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index fa13e35f775d..782b05ca0d0c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3051,12 +3051,15 @@ void hci_adv_monitors_clear(struct hci_dev *hdev)
int handle;
 
idr_for_each_entry(>adv_monitors_idr, monitor, handle)
-   hci_free_adv_monitor(monitor);
+   hci_free_adv_monitor(hdev, monitor);
 
idr_destroy(>adv_monitors_idr);
 }
 
-void hci_free_adv_monitor(struct adv_monitor *monitor)
+/* Frees the monitor structure and do some bookkeepings.
+ * This function requires the caller holds hdev->lock.
+ */
+void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
 {
struct adv_pattern *pattern;
struct adv_pattern *tmp;
@@ -3064,8 +3067,18 @@ void hci_free_adv_monitor(struct adv_monitor *monitor)
if (!monitor)
return;
 
-   list_for_each_entry_safe(pattern, tmp, >patterns, list)
+   list_for_each_entry_safe(pattern, tmp, >patterns, list) {
+   list_del(>list);
kfree(pattern);
+   }
+
+   if (monitor->handle)
+   idr_remove(>adv_monitors_idr, monitor->handle);
+
+   if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED) {
+   hdev->adv_monitors_cnt--;
+   mgmt_adv_monitor_removed(hdev, monitor->handle);
+   }
 
kfree(monitor);
 }
@@ -3075,6 +3088,11 @@ int hci_add_adv_patterns_monitor_complete(struct hci_dev 
*hdev, u8 status)
return mgmt_add_adv_patterns_monitor_complete(hdev, status);
 }
 
+int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
+{
+   return mgmt_remove_adv_monitor_complete(hdev, status);
+}
+
 /* Assigns handle to a monitor, and if offloading is supported and power is on,
  * also attempts to forward the request to the controller.
  * Returns true if request is forwarded (result is pending), false otherwise.
@@ -3121,39 +3139,94 @@ bool hci_add_adv_monitor(struct hci_dev *hdev, struct 
adv_monitor *monitor,
return (*err == 0);
 }
 
-static int free_adv_monitor(int id, void *ptr, void *data)
+/* Attempts to tell the controller and free the monitor. If somehow the
+ * controller doesn't have a corresponding handle, remove anyway.
+ * Returns true if request is forwarded (result is pending), false otherwise.
+ * This function requires the caller

[PATCH v3 5/5] Bluetooth: advmon offload MSFT handle filter enablement

2020-12-15 Thread Archie Pusaka
From: Archie Pusaka 

Implements the feature to disable/enable the filter used for
advertising monitor on MSFT controller, effectively have the same
effect as "remove all monitors" and "add all previously removed
monitors".

This feature would be needed when suspending, where we would not want
to get packets from anything outside the allowlist. Note that the
integration with the suspending part is not included in this patch.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

(no changes since v1)

 net/bluetooth/msft.c | 67 
 net/bluetooth/msft.h |  6 
 2 files changed, 73 insertions(+)

diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index 7e33a85c3f1c..055cc5a260df 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -69,6 +69,17 @@ struct msft_rp_le_cancel_monitor_advertisement {
__u8 sub_opcode;
 } __packed;
 
+#define MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE 0x05
+struct msft_cp_le_set_advertisement_filter_enable {
+   __u8 sub_opcode;
+   __u8 enable;
+} __packed;
+
+struct msft_rp_le_set_advertisement_filter_enable {
+   __u8 status;
+   __u8 sub_opcode;
+} __packed;
+
 struct msft_monitor_advertisement_handle_data {
__u8  msft_handle;
__u16 mgmt_handle;
@@ -85,6 +96,7 @@ struct msft_data {
 
struct {
u8 reregistering:1;
+   u8 filter_enabled:1;
} flags;
 };
 
@@ -193,6 +205,7 @@ void msft_do_open(struct hci_dev *hdev)
 
if (msft_monitor_supported(hdev)) {
msft->flags.reregistering = true;
+   msft_set_filter_enable(hdev, true);
reregister_monitor_on_restart(hdev, 0);
}
 }
@@ -398,6 +411,40 @@ static void msft_le_cancel_monitor_advertisement_cb(struct 
hci_dev *hdev,
hci_remove_adv_monitor_complete(hdev, status);
 }
 
+static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev,
+  u8 status, u16 opcode,
+  struct sk_buff *skb)
+{
+   struct msft_cp_le_set_advertisement_filter_enable *cp;
+   struct msft_rp_le_set_advertisement_filter_enable *rp;
+   struct msft_data *msft = hdev->msft_data;
+
+   rp = (struct msft_rp_le_set_advertisement_filter_enable *)skb->data;
+   if (skb->len < sizeof(*rp))
+   return;
+
+   /* Error 0x0C would be returned if the filter enabled status is
+* already set to whatever we were trying to set.
+* Although the default state should be disabled, some controller set
+* the initial value to enabled. Because there is no way to know the
+* actual initial value before sending this command, here we also treat
+* error 0x0C as success.
+*/
+   if (status != 0x00 && status != 0x0C)
+   return;
+
+   hci_dev_lock(hdev);
+
+   cp = hci_sent_cmd_data(hdev, hdev->msft_opcode);
+   msft->flags.filter_enabled = cp->enable;
+
+   if (status == 0x0C)
+   bt_dev_warn(hdev, "MSFT filter_enable is already %s",
+   cp->enable ? "on" : "off");
+
+   hci_dev_unlock(hdev);
+}
+
 static bool msft_monitor_rssi_valid(struct adv_monitor *monitor)
 {
struct adv_rssi_thresholds *r = >rssi;
@@ -534,3 +581,23 @@ int msft_remove_monitor(struct hci_dev *hdev, struct 
adv_monitor *monitor,
 
return err;
 }
+
+int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
+{
+   struct msft_cp_le_set_advertisement_filter_enable cp;
+   struct hci_request req;
+   struct msft_data *msft = hdev->msft_data;
+   int err;
+
+   if (!msft)
+   return -EOPNOTSUPP;
+
+   cp.sub_opcode = MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE;
+   cp.enable = enable;
+
+   hci_req_init(, hdev);
+   hci_req_add(, hdev->msft_opcode, sizeof(cp), );
+   err = hci_req_run_skb(, msft_le_set_advertisement_filter_enable_cb);
+
+   return err;
+}
diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
index 6f126a1f1688..f8e4d3a6d641 100644
--- a/net/bluetooth/msft.h
+++ b/net/bluetooth/msft.h
@@ -20,6 +20,7 @@ __u64 msft_get_features(struct hci_dev *hdev);
 int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor 
*monitor);
 int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
u16 handle);
+int msft_set_filter_enable(struct hci_dev *hdev, bool enable);
 
 #else
 
@@ -45,4 +46,9 @@ static inline int msft_remove_monitor(struct hci_dev *hdev,
return -EOPNOTSUPP;
 }
 
+static inline int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
+{
+   return -EOPNOTSUPP;
+}
+
 #endif
-- 
2.29.2.684.gfbc64c5ab5-goog



[PATCH v3 2/5] Bluetooth: advmon offload MSFT add monitor

2020-12-15 Thread Archie Pusaka
From: Archie Pusaka 

Enables advertising monitor offloading to the controller, if MSFT
extension is supported. The kernel won't adjust the monitor parameters
to match what the controller supports - that is the user space's
responsibility.

This patch only manages the addition of monitors. Monitor removal is
going to be handled by another patch.

Signed-off-by: Archie Pusaka 
Reviewed-by: Manish Mandlik 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

(no changes since v2)

Changes in v2:
* Also implement the new MGMT opcode and merge the functionality with
  the old one.

 include/net/bluetooth/hci_core.h |  17 ++-
 net/bluetooth/hci_core.c |  54 +++--
 net/bluetooth/mgmt.c | 144 ++
 net/bluetooth/msft.c | 201 ++-
 net/bluetooth/msft.h |  12 ++
 5 files changed, 367 insertions(+), 61 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 8b7cf3620938..879d1e38ce96 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -261,13 +261,20 @@ struct adv_rssi_thresholds {
 struct adv_monitor {
struct list_head patterns;
struct adv_rssi_thresholds rssi;
-   boolactive;
__u16   handle;
+
+   enum {
+   ADV_MONITOR_STATE_NOT_REGISTERED,
+   ADV_MONITOR_STATE_REGISTERED,
+   ADV_MONITOR_STATE_OFFLOADED
+   } state;
 };
 
 #define HCI_MIN_ADV_MONITOR_HANDLE 1
-#define HCI_MAX_ADV_MONITOR_NUM_HANDLES32
+#define HCI_MAX_ADV_MONITOR_NUM_HANDLES32
 #define HCI_MAX_ADV_MONITOR_NUM_PATTERNS   16
+#define HCI_ADV_MONITOR_EXT_NONE   1
+#define HCI_ADV_MONITOR_EXT_MSFT   2
 
 #define HCI_MAX_SHORT_NAME_LENGTH  10
 
@@ -1326,9 +1333,12 @@ void hci_adv_instances_set_rpa_expired(struct hci_dev 
*hdev, bool rpa_expired);
 
 void hci_adv_monitors_clear(struct hci_dev *hdev);
 void hci_free_adv_monitor(struct adv_monitor *monitor);
-int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
+int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
+   int *err);
 int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle);
 bool hci_is_adv_monitoring(struct hci_dev *hdev);
+int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev);
 
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
 
@@ -1804,6 +1814,7 @@ void mgmt_advertising_added(struct sock *sk, struct 
hci_dev *hdev,
 void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
  u8 instance);
 int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
+int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
 
 u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
  u16 to_multiplier);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9d2c9a1c552f..fa13e35f775d 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3070,27 +3070,55 @@ void hci_free_adv_monitor(struct adv_monitor *monitor)
kfree(monitor);
 }
 
-/* This function requires the caller holds hdev->lock */
-int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
+int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)
+{
+   return mgmt_add_adv_patterns_monitor_complete(hdev, status);
+}
+
+/* Assigns handle to a monitor, and if offloading is supported and power is on,
+ * also attempts to forward the request to the controller.
+ * Returns true if request is forwarded (result is pending), false otherwise.
+ * This function requires the caller holds hdev->lock.
+ */
+bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
+int *err)
 {
int min, max, handle;
 
-   if (!monitor)
-   return -EINVAL;
+   *err = 0;
+
+   if (!monitor) {
+   *err = -EINVAL;
+   return false;
+   }
 
min = HCI_MIN_ADV_MONITOR_HANDLE;
max = HCI_MIN_ADV_MONITOR_HANDLE + HCI_MAX_ADV_MONITOR_NUM_HANDLES;
handle = idr_alloc(>adv_monitors_idr, monitor, min, max,
   GFP_KERNEL);
-   if (handle < 0)
-   return handle;
+   if (handle < 0) {
+   *err = handle;
+   return false;
+   }
 
-   hdev->adv_monitors_cnt++;
monitor->handle = handle;
 
-   hci_update_background_scan(hdev);
+   if (!hdev_is_powered(hdev))
+   return false;
 
-   return 0;
+   switch (hci_get_adv_monitor_offload_ext(hdev)) {
+   case HCI_ADV_MONITOR_EXT_NONE:
+   hci_update_background_scan(hdev);
+

[PATCH v3 4/5] Bluetooth: advmon offload MSFT handle controller reset

2020-12-15 Thread Archie Pusaka
From: Archie Pusaka 

When the controller is powered off, the registered advertising monitor
is removed from the controller. This patch handles the re-registration
of those monitors when the power is on.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

(no changes since v1)

 net/bluetooth/msft.c | 79 +---
 1 file changed, 74 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index f5aa0e3b1b9b..7e33a85c3f1c 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -82,8 +82,15 @@ struct msft_data {
struct list_head handle_map;
__u16 pending_add_handle;
__u16 pending_remove_handle;
+
+   struct {
+   u8 reregistering:1;
+   } flags;
 };
 
+static int __msft_add_monitor_pattern(struct hci_dev *hdev,
+ struct adv_monitor *monitor);
+
 bool msft_monitor_supported(struct hci_dev *hdev)
 {
return !!(msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR);
@@ -134,6 +141,35 @@ static bool read_supported_features(struct hci_dev *hdev,
return false;
 }
 
+/* This function requires the caller holds hdev->lock */
+static void reregister_monitor_on_restart(struct hci_dev *hdev, int handle)
+{
+   struct adv_monitor *monitor;
+   struct msft_data *msft = hdev->msft_data;
+   int err;
+
+   while (1) {
+   monitor = idr_get_next(>adv_monitors_idr, );
+   if (!monitor) {
+   /* All monitors have been reregistered */
+   msft->flags.reregistering = false;
+   hci_update_background_scan(hdev);
+   return;
+   }
+
+   msft->pending_add_handle = (u16)handle;
+   err = __msft_add_monitor_pattern(hdev, monitor);
+
+   /* If success, we return and wait for monitor added callback */
+   if (!err)
+   return;
+
+   /* Otherwise remove the monitor and keep registering */
+   hci_free_adv_monitor(hdev, monitor);
+   handle++;
+   }
+}
+
 void msft_do_open(struct hci_dev *hdev)
 {
struct msft_data *msft;
@@ -154,12 +190,18 @@ void msft_do_open(struct hci_dev *hdev)
 
INIT_LIST_HEAD(>handle_map);
hdev->msft_data = msft;
+
+   if (msft_monitor_supported(hdev)) {
+   msft->flags.reregistering = true;
+   reregister_monitor_on_restart(hdev, 0);
+   }
 }
 
 void msft_do_close(struct hci_dev *hdev)
 {
struct msft_data *msft = hdev->msft_data;
struct msft_monitor_advertisement_handle_data *handle_data, *tmp;
+   struct adv_monitor *monitor;
 
if (!msft)
return;
@@ -169,6 +211,12 @@ void msft_do_close(struct hci_dev *hdev)
hdev->msft_data = NULL;
 
list_for_each_entry_safe(handle_data, tmp, >handle_map, list) {
+   monitor = idr_find(>adv_monitors_idr,
+  handle_data->mgmt_handle);
+
+   if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED)
+   monitor->state = ADV_MONITOR_STATE_REGISTERED;
+
list_del(_data->list);
kfree(handle_data);
}
@@ -282,9 +330,15 @@ static void msft_le_monitor_advertisement_cb(struct 
hci_dev *hdev,
if (status && monitor)
hci_free_adv_monitor(hdev, monitor);
 
+   /* If in restart/reregister sequence, keep registering. */
+   if (msft->flags.reregistering)
+   reregister_monitor_on_restart(hdev,
+ msft->pending_add_handle + 1);
+
hci_dev_unlock(hdev);
 
-   hci_add_adv_patterns_monitor_complete(hdev, status);
+   if (!msft->flags.reregistering)
+   hci_add_adv_patterns_monitor_complete(hdev, status);
 }
 
 static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
@@ -374,7 +428,8 @@ static bool msft_monitor_pattern_valid(struct adv_monitor 
*monitor)
 }
 
 /* This function requires the caller holds hdev->lock */
-int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor)
+static int __msft_add_monitor_pattern(struct hci_dev *hdev,
+ struct adv_monitor *monitor)
 {
struct msft_cp_le_monitor_advertisement *cp;
struct msft_le_monitor_advertisement_pattern_data *pattern_data;
@@ -387,9 +442,6 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct 
adv_monitor *monitor)
u8 pattern_count = 0;
int err = 0;
 
-   if (!msft)
-   return -EOPNOTSUPP;
-
if (!msft_monitor_pattern_valid(monitor))
return -EINVAL;
 
@@ -434,6 +486,20 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, s

[PATCH v3 1/5] Bluetooth: advmon offload MSFT add rssi support

2020-12-15 Thread Archie Pusaka
From: Archie Pusaka 

MSFT needs rssi parameter for monitoring advertisement packet,
therefore we should supply them from mgmt. This adds a new opcode
to add advertisement monitor with rssi parameters.

Signed-off-by: Archie Pusaka 
Reviewed-by: Manish Mandlik 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

Changes in v3:
* Flips the order of rssi and pattern_count on mgmt struct

Changes in v2:
* Add a new opcode instead of modifying an existing one

 include/net/bluetooth/hci_core.h |  9 +++
 include/net/bluetooth/mgmt.h | 16 ++
 net/bluetooth/mgmt.c | 99 
 3 files changed, 101 insertions(+), 23 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 677a8c50b2ad..8b7cf3620938 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -250,8 +250,17 @@ struct adv_pattern {
__u8 value[HCI_MAX_AD_LENGTH];
 };
 
+struct adv_rssi_thresholds {
+   __s8 low_threshold;
+   __s8 high_threshold;
+   __u16 low_threshold_timeout;
+   __u16 high_threshold_timeout;
+   __u8 sampling_period;
+};
+
 struct adv_monitor {
struct list_head patterns;
+   struct adv_rssi_thresholds rssi;
boolactive;
__u16   handle;
 };
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index f9a6638e20b3..9917b911a4fb 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -821,6 +821,22 @@ struct mgmt_rp_add_ext_adv_data {
__u8instance;
 } __packed;
 
+struct mgmt_adv_rssi_thresholds {
+   __s8 high_threshold;
+   __le16 high_threshold_timeout;
+   __s8 low_threshold;
+   __le16 low_threshold_timeout;
+   __u8 sampling_period;
+} __packed;
+
+#define MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI  0x0056
+struct mgmt_cp_add_adv_patterns_monitor_rssi {
+   struct mgmt_adv_rssi_thresholds rssi;
+   __u8 pattern_count;
+   struct mgmt_adv_pattern patterns[];
+} __packed;
+#define MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE8
+
 #define MGMT_EV_CMD_COMPLETE   0x0001
 struct mgmt_ev_cmd_complete {
__le16  opcode;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index fa0f7a4a1d2f..cd574054aa39 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -124,6 +124,7 @@ static const u16 mgmt_commands[] = {
MGMT_OP_REMOVE_ADV_MONITOR,
MGMT_OP_ADD_EXT_ADV_PARAMS,
MGMT_OP_ADD_EXT_ADV_DATA,
+   MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI,
 };
 
 static const u16 mgmt_events[] = {
@@ -4225,22 +4226,40 @@ static int read_adv_mon_features(struct sock *sk, 
struct hci_dev *hdev,
return err;
 }
 
-static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
-   void *data, u16 len)
+static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
+ void *data, u16 len, u16 op)
 {
-   struct mgmt_cp_add_adv_patterns_monitor *cp = data;
+   struct mgmt_cp_add_adv_patterns_monitor *cp = NULL;
+   struct mgmt_cp_add_adv_patterns_monitor_rssi *cp_rssi = NULL;
struct mgmt_rp_add_adv_patterns_monitor rp;
+   struct mgmt_adv_rssi_thresholds *rssi = NULL;
+   struct mgmt_adv_pattern *patterns = NULL;
struct adv_monitor *m = NULL;
struct adv_pattern *p = NULL;
unsigned int mp_cnt = 0, prev_adv_monitors_cnt;
__u8 cp_ofst = 0, cp_len = 0;
int err, i;
+   u8 pattern_count;
+   u16 expected_len;
 
BT_DBG("request for %s", hdev->name);
 
-   if (len <= sizeof(*cp) || cp->pattern_count == 0) {
-   err = mgmt_cmd_status(sk, hdev->id,
- MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
+   if (op == MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI) {
+   cp_rssi = data;
+   pattern_count = cp_rssi->pattern_count;
+   rssi = _rssi->rssi;
+   patterns = cp_rssi->patterns;
+   expected_len = sizeof(*cp_rssi) +
+  pattern_count * sizeof(*patterns);
+   } else {
+   cp = data;
+   pattern_count = cp->pattern_count;
+   patterns = cp->patterns;
+   expected_len = sizeof(*cp) + pattern_count * sizeof(*patterns);
+   }
+
+   if (len != expected_len || pattern_count == 0) {
+   err = mgmt_cmd_status(sk, hdev->id, op,
  MGMT_STATUS_INVALID_PARAMS);
goto failed;
}
@@ -4254,21 +4273,40 @@ static int add_adv_patterns_monitor(struct sock *sk, 
struct hci_dev *hdev,
INIT_LIST_HEAD(>patterns);
m->active = false;
 
-   for (i = 0; i < cp->pattern_count; i++) {
+   if (rssi) {
+   m->rssi.low_threshold = rssi->lo

[PATCH v3 0/5] MSFT offloading support for advertisement monitor

2020-12-15 Thread Archie Pusaka
From: Archie Pusaka 


Hi linux-bluetooth,

This series of patches manages the hardware offloading part of MSFT
extension API. The full documentation can be accessed by this link:
https://docs.microsoft.com/en-us/windows-hardware/drivers/bluetooth/microsoft-defined-bluetooth-hci-commands-and-events

Only four of the HCI commands are planned to be implemented:
HCI_VS_MSFT_Read_Supported_Features (implemented in previous patch),
HCI_VS_MSFT_LE_Monitor_Advertisement,
HCI_VS_MSFT_LE_Cancel_Monitor_Advertisement, and
HCI_VS_MSFT_LE_Set_Advertisement_Filter_Enable.
These are the commands which would be used for advertisement monitor
feature. Only if the controller supports the MSFT extension would
these commands be sent. Otherwise, software-based monitoring would be
performed in the user space instead.

Thanks in advance for your feedback!

Archie

Changes in v3:
* Flips the order of rssi and pattern_count on mgmt struct
* Fix return type of msft_remove_monitor

Changes in v2:
* Add a new opcode instead of modifying an existing one
* Also implement the new MGMT opcode and merge the functionality with
  the old one.

Archie Pusaka (5):
  Bluetooth: advmon offload MSFT add rssi support
  Bluetooth: advmon offload MSFT add monitor
  Bluetooth: advmon offload MSFT remove monitor
  Bluetooth: advmon offload MSFT handle controller reset
  Bluetooth: advmon offload MSFT handle filter enablement

 include/net/bluetooth/hci_core.h |  34 ++-
 include/net/bluetooth/mgmt.h |  16 ++
 net/bluetooth/hci_core.c | 173 +---
 net/bluetooth/mgmt.c | 333 --
 net/bluetooth/msft.c | 456 ++-
 net/bluetooth/msft.h |  27 ++
 6 files changed, 919 insertions(+), 120 deletions(-)

-- 
2.29.2.684.gfbc64c5ab5-goog



Re: [PATCH v2 3/5] Bluetooth: advmon offload MSFT remove monitor

2020-12-15 Thread Archie Pusaka
Hi Dan,

On Wed, 16 Dec 2020 at 03:06, Dan Carpenter  wrote:
>
> Hi Archie,
>
> url:
> https://github.com/0day-ci/linux/commits/Archie-Pusaka/MSFT-offloading-support-for-advertisement-monitor/20201215-163858
> base:   
> https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git 
> master
> config: i386-randconfig-m021-20201215 (attached as .config)
> compiler: gcc-9 (Debian 9.3.0-15) 9.3.0
>
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot 
> Reported-by: Dan Carpenter 
>
> smatch warnings:
> net/bluetooth/msft.h:45 msft_remove_monitor() warn: signedness bug returning 
> '(-95)'
>
> vim +45 net/bluetooth/msft.h
>
> d8ca4cbc63c57c8 Archie Pusaka  2020-12-15  41  static inline bool 
> msft_remove_monitor(struct hci_dev *hdev,
>      
> d8ca4cbc63c57c8 Archie Pusaka  2020-12-15  42         
>  struct adv_monitor *monitor,
> d8ca4cbc63c57c8 Archie Pusaka  2020-12-15  43 
>  u16 handle)
> d8ca4cbc63c57c8 Archie Pusaka  2020-12-15  44  {
> d8ca4cbc63c57c8 Archie Pusaka  2020-12-15 @45   return -EOPNOTSUPP;
>     ^^^^^^^
> change this to return false?
>
Thanks. Will fix.

> d8ca4cbc63c57c8 Archie Pusaka  2020-12-15  46  }
>
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/kbuild-...@lists.01.org

Regards,
Archie


[PATCH v2 2/5] Bluetooth: advmon offload MSFT add monitor

2020-12-15 Thread Archie Pusaka
From: Archie Pusaka 

Enables advertising monitor offloading to the controller, if MSFT
extension is supported. The kernel won't adjust the monitor parameters
to match what the controller supports - that is the user space's
responsibility.

This patch only manages the addition of monitors. Monitor removal is
going to be handled by another patch.

Signed-off-by: Archie Pusaka 
Reviewed-by: Manish Mandlik 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

Changes in v2:
* Also implement the new MGMT opcode and merge the functionality with
  the old one.

 include/net/bluetooth/hci_core.h |  17 ++-
 net/bluetooth/hci_core.c |  54 +++--
 net/bluetooth/mgmt.c | 144 ++
 net/bluetooth/msft.c | 201 ++-
 net/bluetooth/msft.h |  12 ++
 5 files changed, 367 insertions(+), 61 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 8b7cf3620938..879d1e38ce96 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -261,13 +261,20 @@ struct adv_rssi_thresholds {
 struct adv_monitor {
struct list_head patterns;
struct adv_rssi_thresholds rssi;
-   boolactive;
__u16   handle;
+
+   enum {
+   ADV_MONITOR_STATE_NOT_REGISTERED,
+   ADV_MONITOR_STATE_REGISTERED,
+   ADV_MONITOR_STATE_OFFLOADED
+   } state;
 };
 
 #define HCI_MIN_ADV_MONITOR_HANDLE 1
-#define HCI_MAX_ADV_MONITOR_NUM_HANDLES32
+#define HCI_MAX_ADV_MONITOR_NUM_HANDLES32
 #define HCI_MAX_ADV_MONITOR_NUM_PATTERNS   16
+#define HCI_ADV_MONITOR_EXT_NONE   1
+#define HCI_ADV_MONITOR_EXT_MSFT   2
 
 #define HCI_MAX_SHORT_NAME_LENGTH  10
 
@@ -1326,9 +1333,12 @@ void hci_adv_instances_set_rpa_expired(struct hci_dev 
*hdev, bool rpa_expired);
 
 void hci_adv_monitors_clear(struct hci_dev *hdev);
 void hci_free_adv_monitor(struct adv_monitor *monitor);
-int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
+int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
+   int *err);
 int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle);
 bool hci_is_adv_monitoring(struct hci_dev *hdev);
+int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev);
 
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
 
@@ -1804,6 +1814,7 @@ void mgmt_advertising_added(struct sock *sk, struct 
hci_dev *hdev,
 void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
  u8 instance);
 int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
+int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
 
 u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
  u16 to_multiplier);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9d2c9a1c552f..fa13e35f775d 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3070,27 +3070,55 @@ void hci_free_adv_monitor(struct adv_monitor *monitor)
kfree(monitor);
 }
 
-/* This function requires the caller holds hdev->lock */
-int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
+int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)
+{
+   return mgmt_add_adv_patterns_monitor_complete(hdev, status);
+}
+
+/* Assigns handle to a monitor, and if offloading is supported and power is on,
+ * also attempts to forward the request to the controller.
+ * Returns true if request is forwarded (result is pending), false otherwise.
+ * This function requires the caller holds hdev->lock.
+ */
+bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
+int *err)
 {
int min, max, handle;
 
-   if (!monitor)
-   return -EINVAL;
+   *err = 0;
+
+   if (!monitor) {
+   *err = -EINVAL;
+   return false;
+   }
 
min = HCI_MIN_ADV_MONITOR_HANDLE;
max = HCI_MIN_ADV_MONITOR_HANDLE + HCI_MAX_ADV_MONITOR_NUM_HANDLES;
handle = idr_alloc(>adv_monitors_idr, monitor, min, max,
   GFP_KERNEL);
-   if (handle < 0)
-   return handle;
+   if (handle < 0) {
+   *err = handle;
+   return false;
+   }
 
-   hdev->adv_monitors_cnt++;
monitor->handle = handle;
 
-   hci_update_background_scan(hdev);
+   if (!hdev_is_powered(hdev))
+   return false;
 
-   return 0;
+   switch (hci_get_adv_monitor_offload_ext(hdev)) {
+   case HCI_ADV_MONITOR_EXT_NONE:
+   hci_update_background_scan(hdev);
+   BT_DBG("%s ad

[PATCH v2 4/5] Bluetooth: advmon offload MSFT handle controller reset

2020-12-15 Thread Archie Pusaka
From: Archie Pusaka 

When the controller is powered off, the registered advertising monitor
is removed from the controller. This patch handles the re-registration
of those monitors when the power is on.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

(no changes since v1)

 net/bluetooth/msft.c | 79 +---
 1 file changed, 74 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index f5aa0e3b1b9b..7e33a85c3f1c 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -82,8 +82,15 @@ struct msft_data {
struct list_head handle_map;
__u16 pending_add_handle;
__u16 pending_remove_handle;
+
+   struct {
+   u8 reregistering:1;
+   } flags;
 };
 
+static int __msft_add_monitor_pattern(struct hci_dev *hdev,
+ struct adv_monitor *monitor);
+
 bool msft_monitor_supported(struct hci_dev *hdev)
 {
return !!(msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR);
@@ -134,6 +141,35 @@ static bool read_supported_features(struct hci_dev *hdev,
return false;
 }
 
+/* This function requires the caller holds hdev->lock */
+static void reregister_monitor_on_restart(struct hci_dev *hdev, int handle)
+{
+   struct adv_monitor *monitor;
+   struct msft_data *msft = hdev->msft_data;
+   int err;
+
+   while (1) {
+   monitor = idr_get_next(>adv_monitors_idr, );
+   if (!monitor) {
+   /* All monitors have been reregistered */
+   msft->flags.reregistering = false;
+   hci_update_background_scan(hdev);
+   return;
+   }
+
+   msft->pending_add_handle = (u16)handle;
+   err = __msft_add_monitor_pattern(hdev, monitor);
+
+   /* If success, we return and wait for monitor added callback */
+   if (!err)
+   return;
+
+   /* Otherwise remove the monitor and keep registering */
+   hci_free_adv_monitor(hdev, monitor);
+   handle++;
+   }
+}
+
 void msft_do_open(struct hci_dev *hdev)
 {
struct msft_data *msft;
@@ -154,12 +190,18 @@ void msft_do_open(struct hci_dev *hdev)
 
INIT_LIST_HEAD(>handle_map);
hdev->msft_data = msft;
+
+   if (msft_monitor_supported(hdev)) {
+   msft->flags.reregistering = true;
+   reregister_monitor_on_restart(hdev, 0);
+   }
 }
 
 void msft_do_close(struct hci_dev *hdev)
 {
struct msft_data *msft = hdev->msft_data;
struct msft_monitor_advertisement_handle_data *handle_data, *tmp;
+   struct adv_monitor *monitor;
 
if (!msft)
return;
@@ -169,6 +211,12 @@ void msft_do_close(struct hci_dev *hdev)
hdev->msft_data = NULL;
 
list_for_each_entry_safe(handle_data, tmp, >handle_map, list) {
+   monitor = idr_find(>adv_monitors_idr,
+  handle_data->mgmt_handle);
+
+   if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED)
+   monitor->state = ADV_MONITOR_STATE_REGISTERED;
+
list_del(_data->list);
kfree(handle_data);
}
@@ -282,9 +330,15 @@ static void msft_le_monitor_advertisement_cb(struct 
hci_dev *hdev,
if (status && monitor)
hci_free_adv_monitor(hdev, monitor);
 
+   /* If in restart/reregister sequence, keep registering. */
+   if (msft->flags.reregistering)
+   reregister_monitor_on_restart(hdev,
+ msft->pending_add_handle + 1);
+
hci_dev_unlock(hdev);
 
-   hci_add_adv_patterns_monitor_complete(hdev, status);
+   if (!msft->flags.reregistering)
+   hci_add_adv_patterns_monitor_complete(hdev, status);
 }
 
 static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
@@ -374,7 +428,8 @@ static bool msft_monitor_pattern_valid(struct adv_monitor 
*monitor)
 }
 
 /* This function requires the caller holds hdev->lock */
-int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor)
+static int __msft_add_monitor_pattern(struct hci_dev *hdev,
+ struct adv_monitor *monitor)
 {
struct msft_cp_le_monitor_advertisement *cp;
struct msft_le_monitor_advertisement_pattern_data *pattern_data;
@@ -387,9 +442,6 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct 
adv_monitor *monitor)
u8 pattern_count = 0;
int err = 0;
 
-   if (!msft)
-   return -EOPNOTSUPP;
-
if (!msft_monitor_pattern_valid(monitor))
return -EINVAL;
 
@@ -434,6 +486,20 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, s

[PATCH v2 5/5] Bluetooth: advmon offload MSFT handle filter enablement

2020-12-15 Thread Archie Pusaka
From: Archie Pusaka 

Implements the feature to disable/enable the filter used for
advertising monitor on MSFT controller, effectively have the same
effect as "remove all monitors" and "add all previously removed
monitors".

This feature would be needed when suspending, where we would not want
to get packets from anything outside the allowlist. Note that the
integration with the suspending part is not included in this patch.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

(no changes since v1)

 net/bluetooth/msft.c | 67 
 net/bluetooth/msft.h |  6 
 2 files changed, 73 insertions(+)

diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index 7e33a85c3f1c..055cc5a260df 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -69,6 +69,17 @@ struct msft_rp_le_cancel_monitor_advertisement {
__u8 sub_opcode;
 } __packed;
 
+#define MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE 0x05
+struct msft_cp_le_set_advertisement_filter_enable {
+   __u8 sub_opcode;
+   __u8 enable;
+} __packed;
+
+struct msft_rp_le_set_advertisement_filter_enable {
+   __u8 status;
+   __u8 sub_opcode;
+} __packed;
+
 struct msft_monitor_advertisement_handle_data {
__u8  msft_handle;
__u16 mgmt_handle;
@@ -85,6 +96,7 @@ struct msft_data {
 
struct {
u8 reregistering:1;
+   u8 filter_enabled:1;
} flags;
 };
 
@@ -193,6 +205,7 @@ void msft_do_open(struct hci_dev *hdev)
 
if (msft_monitor_supported(hdev)) {
msft->flags.reregistering = true;
+   msft_set_filter_enable(hdev, true);
reregister_monitor_on_restart(hdev, 0);
}
 }
@@ -398,6 +411,40 @@ static void msft_le_cancel_monitor_advertisement_cb(struct 
hci_dev *hdev,
hci_remove_adv_monitor_complete(hdev, status);
 }
 
+static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev,
+  u8 status, u16 opcode,
+  struct sk_buff *skb)
+{
+   struct msft_cp_le_set_advertisement_filter_enable *cp;
+   struct msft_rp_le_set_advertisement_filter_enable *rp;
+   struct msft_data *msft = hdev->msft_data;
+
+   rp = (struct msft_rp_le_set_advertisement_filter_enable *)skb->data;
+   if (skb->len < sizeof(*rp))
+   return;
+
+   /* Error 0x0C would be returned if the filter enabled status is
+* already set to whatever we were trying to set.
+* Although the default state should be disabled, some controller set
+* the initial value to enabled. Because there is no way to know the
+* actual initial value before sending this command, here we also treat
+* error 0x0C as success.
+*/
+   if (status != 0x00 && status != 0x0C)
+   return;
+
+   hci_dev_lock(hdev);
+
+   cp = hci_sent_cmd_data(hdev, hdev->msft_opcode);
+   msft->flags.filter_enabled = cp->enable;
+
+   if (status == 0x0C)
+   bt_dev_warn(hdev, "MSFT filter_enable is already %s",
+   cp->enable ? "on" : "off");
+
+   hci_dev_unlock(hdev);
+}
+
 static bool msft_monitor_rssi_valid(struct adv_monitor *monitor)
 {
struct adv_rssi_thresholds *r = >rssi;
@@ -534,3 +581,23 @@ int msft_remove_monitor(struct hci_dev *hdev, struct 
adv_monitor *monitor,
 
return err;
 }
+
+int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
+{
+   struct msft_cp_le_set_advertisement_filter_enable cp;
+   struct hci_request req;
+   struct msft_data *msft = hdev->msft_data;
+   int err;
+
+   if (!msft)
+   return -EOPNOTSUPP;
+
+   cp.sub_opcode = MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE;
+   cp.enable = enable;
+
+   hci_req_init(, hdev);
+   hci_req_add(, hdev->msft_opcode, sizeof(cp), );
+   err = hci_req_run_skb(, msft_le_set_advertisement_filter_enable_cb);
+
+   return err;
+}
diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
index 9f9a11f90b0c..44bee705c16d 100644
--- a/net/bluetooth/msft.h
+++ b/net/bluetooth/msft.h
@@ -20,6 +20,7 @@ __u64 msft_get_features(struct hci_dev *hdev);
 int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor 
*monitor);
 int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
u16 handle);
+int msft_set_filter_enable(struct hci_dev *hdev, bool enable);
 
 #else
 
@@ -45,4 +46,9 @@ static inline bool msft_remove_monitor(struct hci_dev *hdev,
return -EOPNOTSUPP;
 }
 
+static inline int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
+{
+   return -EOPNOTSUPP;
+}
+
 #endif
-- 
2.29.2.684.gfbc64c5ab5-goog



[PATCH v2 3/5] Bluetooth: advmon offload MSFT remove monitor

2020-12-15 Thread Archie Pusaka
From: Archie Pusaka 

Implements the monitor removal functionality for advertising monitor
offloading to MSFT controllers. Supply handle = 0 to remove all
monitors.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

(no changes since v1)

 include/net/bluetooth/hci_core.h |   8 +-
 net/bluetooth/hci_core.c | 119 +++--
 net/bluetooth/mgmt.c | 110 +-
 net/bluetooth/msft.c | 127 ++-
 net/bluetooth/msft.h |   9 +++
 5 files changed, 323 insertions(+), 50 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 879d1e38ce96..29cfc6a2d689 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1332,11 +1332,13 @@ int hci_remove_adv_instance(struct hci_dev *hdev, u8 
instance);
 void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired);
 
 void hci_adv_monitors_clear(struct hci_dev *hdev);
-void hci_free_adv_monitor(struct adv_monitor *monitor);
+void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
 int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
 bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
int *err);
-int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle);
+bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err);
+bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err);
 bool hci_is_adv_monitoring(struct hci_dev *hdev);
 int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev);
 
@@ -1813,8 +1815,10 @@ void mgmt_advertising_added(struct sock *sk, struct 
hci_dev *hdev,
u8 instance);
 void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
  u8 instance);
+void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle);
 int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
 int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
 
 u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
  u16 to_multiplier);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index fa13e35f775d..782b05ca0d0c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3051,12 +3051,15 @@ void hci_adv_monitors_clear(struct hci_dev *hdev)
int handle;
 
idr_for_each_entry(>adv_monitors_idr, monitor, handle)
-   hci_free_adv_monitor(monitor);
+   hci_free_adv_monitor(hdev, monitor);
 
idr_destroy(>adv_monitors_idr);
 }
 
-void hci_free_adv_monitor(struct adv_monitor *monitor)
+/* Frees the monitor structure and do some bookkeepings.
+ * This function requires the caller holds hdev->lock.
+ */
+void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
 {
struct adv_pattern *pattern;
struct adv_pattern *tmp;
@@ -3064,8 +3067,18 @@ void hci_free_adv_monitor(struct adv_monitor *monitor)
if (!monitor)
return;
 
-   list_for_each_entry_safe(pattern, tmp, >patterns, list)
+   list_for_each_entry_safe(pattern, tmp, >patterns, list) {
+   list_del(>list);
kfree(pattern);
+   }
+
+   if (monitor->handle)
+   idr_remove(>adv_monitors_idr, monitor->handle);
+
+   if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED) {
+   hdev->adv_monitors_cnt--;
+   mgmt_adv_monitor_removed(hdev, monitor->handle);
+   }
 
kfree(monitor);
 }
@@ -3075,6 +3088,11 @@ int hci_add_adv_patterns_monitor_complete(struct hci_dev 
*hdev, u8 status)
return mgmt_add_adv_patterns_monitor_complete(hdev, status);
 }
 
+int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
+{
+   return mgmt_remove_adv_monitor_complete(hdev, status);
+}
+
 /* Assigns handle to a monitor, and if offloading is supported and power is on,
  * also attempts to forward the request to the controller.
  * Returns true if request is forwarded (result is pending), false otherwise.
@@ -3121,39 +3139,94 @@ bool hci_add_adv_monitor(struct hci_dev *hdev, struct 
adv_monitor *monitor,
return (*err == 0);
 }
 
-static int free_adv_monitor(int id, void *ptr, void *data)
+/* Attempts to tell the controller and free the monitor. If somehow the
+ * controller doesn't have a corresponding handle, remove anyway.
+ * Returns true if request is forwarded (result is pending), false otherwise.
+ * This function requires the caller holds hdev->lock.
+ */
+static bool hci_remove_adv_monitor(struct hci_dev *hdev,
+ 

[PATCH v2 1/5] Bluetooth: advmon offload MSFT add rssi support

2020-12-15 Thread Archie Pusaka
From: Archie Pusaka 

MSFT needs rssi parameter for monitoring advertisement packet,
therefore we should supply them from mgmt. This adds a new opcode
to add advertisement monitor with rssi parameters.

Signed-off-by: Archie Pusaka 
Reviewed-by: Manish Mandlik 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

Changes in v2:
* Add a new opcode instead of modifying an existing one

 include/net/bluetooth/hci_core.h |  9 +++
 include/net/bluetooth/mgmt.h | 16 ++
 net/bluetooth/mgmt.c | 99 
 3 files changed, 101 insertions(+), 23 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 677a8c50b2ad..8b7cf3620938 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -250,8 +250,17 @@ struct adv_pattern {
__u8 value[HCI_MAX_AD_LENGTH];
 };
 
+struct adv_rssi_thresholds {
+   __s8 low_threshold;
+   __s8 high_threshold;
+   __u16 low_threshold_timeout;
+   __u16 high_threshold_timeout;
+   __u8 sampling_period;
+};
+
 struct adv_monitor {
struct list_head patterns;
+   struct adv_rssi_thresholds rssi;
boolactive;
__u16   handle;
 };
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index f9a6638e20b3..f3b1460b463d 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -821,6 +821,22 @@ struct mgmt_rp_add_ext_adv_data {
__u8instance;
 } __packed;
 
+struct mgmt_adv_rssi_thresholds {
+   __s8 high_threshold;
+   __le16 high_threshold_timeout;
+   __s8 low_threshold;
+   __le16 low_threshold_timeout;
+   __u8 sampling_period;
+} __packed;
+
+#define MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI  0x0056
+struct mgmt_cp_add_adv_patterns_monitor_rssi {
+   __u8 pattern_count;
+   struct mgmt_adv_rssi_thresholds rssi;
+   struct mgmt_adv_pattern patterns[];
+} __packed;
+#define MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE8
+
 #define MGMT_EV_CMD_COMPLETE   0x0001
 struct mgmt_ev_cmd_complete {
__le16  opcode;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index fa0f7a4a1d2f..cd574054aa39 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -124,6 +124,7 @@ static const u16 mgmt_commands[] = {
MGMT_OP_REMOVE_ADV_MONITOR,
MGMT_OP_ADD_EXT_ADV_PARAMS,
MGMT_OP_ADD_EXT_ADV_DATA,
+   MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI,
 };
 
 static const u16 mgmt_events[] = {
@@ -4225,22 +4226,40 @@ static int read_adv_mon_features(struct sock *sk, 
struct hci_dev *hdev,
return err;
 }
 
-static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
-   void *data, u16 len)
+static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
+ void *data, u16 len, u16 op)
 {
-   struct mgmt_cp_add_adv_patterns_monitor *cp = data;
+   struct mgmt_cp_add_adv_patterns_monitor *cp = NULL;
+   struct mgmt_cp_add_adv_patterns_monitor_rssi *cp_rssi = NULL;
struct mgmt_rp_add_adv_patterns_monitor rp;
+   struct mgmt_adv_rssi_thresholds *rssi = NULL;
+   struct mgmt_adv_pattern *patterns = NULL;
struct adv_monitor *m = NULL;
struct adv_pattern *p = NULL;
unsigned int mp_cnt = 0, prev_adv_monitors_cnt;
__u8 cp_ofst = 0, cp_len = 0;
int err, i;
+   u8 pattern_count;
+   u16 expected_len;
 
BT_DBG("request for %s", hdev->name);
 
-   if (len <= sizeof(*cp) || cp->pattern_count == 0) {
-   err = mgmt_cmd_status(sk, hdev->id,
- MGMT_OP_ADD_ADV_PATTERNS_MONITOR,
+   if (op == MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI) {
+   cp_rssi = data;
+   pattern_count = cp_rssi->pattern_count;
+   rssi = _rssi->rssi;
+   patterns = cp_rssi->patterns;
+   expected_len = sizeof(*cp_rssi) +
+  pattern_count * sizeof(*patterns);
+   } else {
+   cp = data;
+   pattern_count = cp->pattern_count;
+   patterns = cp->patterns;
+   expected_len = sizeof(*cp) + pattern_count * sizeof(*patterns);
+   }
+
+   if (len != expected_len || pattern_count == 0) {
+   err = mgmt_cmd_status(sk, hdev->id, op,
  MGMT_STATUS_INVALID_PARAMS);
goto failed;
}
@@ -4254,21 +4273,40 @@ static int add_adv_patterns_monitor(struct sock *sk, 
struct hci_dev *hdev,
INIT_LIST_HEAD(>patterns);
m->active = false;
 
-   for (i = 0; i < cp->pattern_count; i++) {
+   if (rssi) {
+   m->rssi.low_threshold = rssi->low_threshold;
+   m->rssi.low_threshold_timeout =
+   

[PATCH v2 0/5] MSFT offloading support for advertisement monitor

2020-12-15 Thread Archie Pusaka
From: Archie Pusaka 


Hi linux-bluetooth,

This series of patches manages the hardware offloading part of MSFT
extension API. The full documentation can be accessed by this link:
https://docs.microsoft.com/en-us/windows-hardware/drivers/bluetooth/microsoft-defined-bluetooth-hci-commands-and-events

Only four of the HCI commands are planned to be implemented:
HCI_VS_MSFT_Read_Supported_Features (implemented in previous patch),
HCI_VS_MSFT_LE_Monitor_Advertisement,
HCI_VS_MSFT_LE_Cancel_Monitor_Advertisement, and
HCI_VS_MSFT_LE_Set_Advertisement_Filter_Enable.
These are the commands which would be used for advertisement monitor
feature. Only if the controller supports the MSFT extension would
these commands be sent. Otherwise, software-based monitoring would be
performed in the user space instead.

Thanks in advance for your feedback!

Archie

Changes in v2:
* Add a new opcode instead of modifying an existing one
* Also implement the new MGMT opcode and merge the functionality with
  the old one.

Archie Pusaka (5):
  Bluetooth: advmon offload MSFT add rssi support
  Bluetooth: advmon offload MSFT add monitor
  Bluetooth: advmon offload MSFT remove monitor
  Bluetooth: advmon offload MSFT handle controller reset
  Bluetooth: advmon offload MSFT handle filter enablement

 include/net/bluetooth/hci_core.h |  34 ++-
 include/net/bluetooth/mgmt.h |  16 ++
 net/bluetooth/hci_core.c | 173 +---
 net/bluetooth/mgmt.c | 333 --
 net/bluetooth/msft.c | 456 ++-
 net/bluetooth/msft.h |  27 ++
 6 files changed, 919 insertions(+), 120 deletions(-)

-- 
2.29.2.684.gfbc64c5ab5-goog



Re: [PATCH v1 1/5] Bluetooth: advmon offload MSFT add rssi support

2020-12-07 Thread Archie Pusaka
Hi Marcel,

On Mon, 7 Dec 2020 at 17:57, Marcel Holtmann  wrote:
>
> Hi Archie,
>
> >>>>> MSFT needs rssi parameter for monitoring advertisement packet,
> >>>>> therefore we should supply them from mgmt.
> >>>>>
> >>>>> Signed-off-by: Archie Pusaka 
> >>>>> Reviewed-by: Miao-chen Chou 
> >>>>> Reviewed-by: Yun-Hao Chung 
> >>>>
> >>>> I don’t need any Reviewed-by if they are not catching an obvious user 
> >>>> API breakage.
> >>>>
> >>>>> ---
> >>>>>
> >>>>> include/net/bluetooth/hci_core.h | 9 +
> >>>>> include/net/bluetooth/mgmt.h | 9 +
> >>>>> net/bluetooth/mgmt.c | 8 
> >>>>> 3 files changed, 26 insertions(+)
> >>>>>
> >>>>> diff --git a/include/net/bluetooth/hci_core.h 
> >>>>> b/include/net/bluetooth/hci_core.h
> >>>>> index 9873e1c8cd16..42d446417817 100644
> >>>>> --- a/include/net/bluetooth/hci_core.h
> >>>>> +++ b/include/net/bluetooth/hci_core.h
> >>>>> @@ -246,8 +246,17 @@ struct adv_pattern {
> >>>>> __u8 value[HCI_MAX_AD_LENGTH];
> >>>>> };
> >>>>>
> >>>>> +struct adv_rssi_thresholds {
> >>>>> + __s8 low_threshold;
> >>>>> + __s8 high_threshold;
> >>>>> + __u16 low_threshold_timeout;
> >>>>> + __u16 high_threshold_timeout;
> >>>>> + __u8 sampling_period;
> >>>>> +};
> >>>>> +
> >>>>> struct adv_monitor {
> >>>>> struct list_head patterns;
> >>>>> + struct adv_rssi_thresholds rssi;
> >>>>> boolactive;
> >>>>> __u16   handle;
> >>>>> };
> >>>>> diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
> >>>>> index d8367850e8cd..dc534837be0e 100644
> >>>>> --- a/include/net/bluetooth/mgmt.h
> >>>>> +++ b/include/net/bluetooth/mgmt.h
> >>>>> @@ -763,9 +763,18 @@ struct mgmt_adv_pattern {
> >>>>> __u8 value[31];
> >>>>> } __packed;
> >>>>>
> >>>>> +struct mgmt_adv_rssi_thresholds {
> >>>>> + __s8 high_threshold;
> >>>>> + __le16 high_threshold_timeout;
> >>>>> + __s8 low_threshold;
> >>>>> + __le16 low_threshold_timeout;
> >>>>> + __u8 sampling_period;
> >>>>> +} __packed;
> >>>>> +
> >>>>> #define MGMT_OP_ADD_ADV_PATTERNS_MONITOR  0x0052
> >>>>> struct mgmt_cp_add_adv_patterns_monitor {
> >>>>> __u8 pattern_count;
> >>>>> + struct mgmt_adv_rssi_thresholds rssi;
> >>>>> struct mgmt_adv_pattern patterns[];
> >>>>> } __packed;
> >>>>
> >>>> This is something we can not do. It breaks an userspace facing API. Is 
> >>>> the mgmt opcode 0x0052 in an already released kernel?
> >>>
> >>> Yes, the opcode does exist in an already released kernel.
> >>>
> >>> The DBus method which accesses this API is put behind the experimental
> >>> flag, therefore we expect they are flexible enough to support changes.
> >>> Previously, we already had a discussion in an email thread with the
> >>> title "Offload RSSI tracking to controller", and the outcome supports
> >>> this change.
> >>>
> >>> Here is an excerpt of the discussion.
> >>
> >> it doesn’t matter. This is fixed API now and so we can not just change it. 
> >> The argument above is void. What matters if it is in already released 
> >> kernel.
> >
> > If that is the case, do you have a suggestion to allow RSSI to be
> > considered when monitoring advertisement? Would a new MGMT opcode with
> > these parameters suffice?
>
> its the only way.

I will make the necessary changes. Thanks for the confirmation.

Regards,
Archie

>
> Regards
>
> Marcel
>


Re: [PATCH v1 1/5] Bluetooth: advmon offload MSFT add rssi support

2020-12-04 Thread Archie Pusaka
Hi Marcel,

On Fri, 4 Dec 2020 at 17:51, Marcel Holtmann  wrote:
>
> Hi Archie,
>
> >>> MSFT needs rssi parameter for monitoring advertisement packet,
> >>> therefore we should supply them from mgmt.
> >>>
> >>> Signed-off-by: Archie Pusaka 
> >>> Reviewed-by: Miao-chen Chou 
> >>> Reviewed-by: Yun-Hao Chung 
> >>
> >> I don’t need any Reviewed-by if they are not catching an obvious user API 
> >> breakage.
> >>
> >>> ---
> >>>
> >>> include/net/bluetooth/hci_core.h | 9 +
> >>> include/net/bluetooth/mgmt.h | 9 +
> >>> net/bluetooth/mgmt.c | 8 
> >>> 3 files changed, 26 insertions(+)
> >>>
> >>> diff --git a/include/net/bluetooth/hci_core.h 
> >>> b/include/net/bluetooth/hci_core.h
> >>> index 9873e1c8cd16..42d446417817 100644
> >>> --- a/include/net/bluetooth/hci_core.h
> >>> +++ b/include/net/bluetooth/hci_core.h
> >>> @@ -246,8 +246,17 @@ struct adv_pattern {
> >>>  __u8 value[HCI_MAX_AD_LENGTH];
> >>> };
> >>>
> >>> +struct adv_rssi_thresholds {
> >>> + __s8 low_threshold;
> >>> + __s8 high_threshold;
> >>> + __u16 low_threshold_timeout;
> >>> + __u16 high_threshold_timeout;
> >>> + __u8 sampling_period;
> >>> +};
> >>> +
> >>> struct adv_monitor {
> >>>  struct list_head patterns;
> >>> + struct adv_rssi_thresholds rssi;
> >>>  boolactive;
> >>>  __u16   handle;
> >>> };
> >>> diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
> >>> index d8367850e8cd..dc534837be0e 100644
> >>> --- a/include/net/bluetooth/mgmt.h
> >>> +++ b/include/net/bluetooth/mgmt.h
> >>> @@ -763,9 +763,18 @@ struct mgmt_adv_pattern {
> >>>  __u8 value[31];
> >>> } __packed;
> >>>
> >>> +struct mgmt_adv_rssi_thresholds {
> >>> + __s8 high_threshold;
> >>> + __le16 high_threshold_timeout;
> >>> + __s8 low_threshold;
> >>> + __le16 low_threshold_timeout;
> >>> + __u8 sampling_period;
> >>> +} __packed;
> >>> +
> >>> #define MGMT_OP_ADD_ADV_PATTERNS_MONITOR  0x0052
> >>> struct mgmt_cp_add_adv_patterns_monitor {
> >>>  __u8 pattern_count;
> >>> + struct mgmt_adv_rssi_thresholds rssi;
> >>>  struct mgmt_adv_pattern patterns[];
> >>> } __packed;
> >>
> >> This is something we can not do. It breaks an userspace facing API. Is the 
> >> mgmt opcode 0x0052 in an already released kernel?
> >
> > Yes, the opcode does exist in an already released kernel.
> >
> > The DBus method which accesses this API is put behind the experimental
> > flag, therefore we expect they are flexible enough to support changes.
> > Previously, we already had a discussion in an email thread with the
> > title "Offload RSSI tracking to controller", and the outcome supports
> > this change.
> >
> > Here is an excerpt of the discussion.
>
> it doesn’t matter. This is fixed API now and so we can not just change it. 
> The argument above is void. What matters if it is in already released kernel.

If that is the case, do you have a suggestion to allow RSSI to be
considered when monitoring advertisement? Would a new MGMT opcode with
these parameters suffice?
#define MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI 0x005?
struct mgmt_cp_add_adv_patterns_monitor {
__u8 pattern_count;
struct mgmt_adv_rssi_thresholds rssi;
struct mgmt_adv_pattern patterns[];
} __packed;

Thanks,
Archie


Re: [PATCH v1 1/5] Bluetooth: advmon offload MSFT add rssi support

2020-12-03 Thread Archie Pusaka
Hi Marcel,

On Thu, 3 Dec 2020 at 22:03, Marcel Holtmann  wrote:
>
> Hi Archie,
>
> > MSFT needs rssi parameter for monitoring advertisement packet,
> > therefore we should supply them from mgmt.
> >
> > Signed-off-by: Archie Pusaka 
> > Reviewed-by: Miao-chen Chou 
> > Reviewed-by: Yun-Hao Chung 
>
> I don’t need any Reviewed-by if they are not catching an obvious user API 
> breakage.
>
> > ---
> >
> > include/net/bluetooth/hci_core.h | 9 +
> > include/net/bluetooth/mgmt.h | 9 +
> > net/bluetooth/mgmt.c | 8 
> > 3 files changed, 26 insertions(+)
> >
> > diff --git a/include/net/bluetooth/hci_core.h 
> > b/include/net/bluetooth/hci_core.h
> > index 9873e1c8cd16..42d446417817 100644
> > --- a/include/net/bluetooth/hci_core.h
> > +++ b/include/net/bluetooth/hci_core.h
> > @@ -246,8 +246,17 @@ struct adv_pattern {
> >   __u8 value[HCI_MAX_AD_LENGTH];
> > };
> >
> > +struct adv_rssi_thresholds {
> > + __s8 low_threshold;
> > + __s8 high_threshold;
> > + __u16 low_threshold_timeout;
> > + __u16 high_threshold_timeout;
> > + __u8 sampling_period;
> > +};
> > +
> > struct adv_monitor {
> >   struct list_head patterns;
> > + struct adv_rssi_thresholds rssi;
> >   boolactive;
> >   __u16   handle;
> > };
> > diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
> > index d8367850e8cd..dc534837be0e 100644
> > --- a/include/net/bluetooth/mgmt.h
> > +++ b/include/net/bluetooth/mgmt.h
> > @@ -763,9 +763,18 @@ struct mgmt_adv_pattern {
> >   __u8 value[31];
> > } __packed;
> >
> > +struct mgmt_adv_rssi_thresholds {
> > + __s8 high_threshold;
> > + __le16 high_threshold_timeout;
> > + __s8 low_threshold;
> > + __le16 low_threshold_timeout;
> > + __u8 sampling_period;
> > +} __packed;
> > +
> > #define MGMT_OP_ADD_ADV_PATTERNS_MONITOR  0x0052
> > struct mgmt_cp_add_adv_patterns_monitor {
> >   __u8 pattern_count;
> > + struct mgmt_adv_rssi_thresholds rssi;
> >   struct mgmt_adv_pattern patterns[];
> > } __packed;
>
> This is something we can not do. It breaks an userspace facing API. Is the 
> mgmt opcode 0x0052 in an already released kernel?

Yes, the opcode does exist in an already released kernel.

The DBus method which accesses this API is put behind the experimental
flag, therefore we expect they are flexible enough to support changes.
Previously, we already had a discussion in an email thread with the
title "Offload RSSI tracking to controller", and the outcome supports
this change.

Here is an excerpt of the discussion.
On Thu, 1 Oct 2020 at 05:58, Miao-chen Chou  wrote:
>
> Hi Luiz,
>
> Yes, the RSSI is included as a part of the Adv monitor API, and the RSSI 
> tracking is currently implemented (the patch series is still under review) in 
> bluetoothd and used by bluetoothctl (submenu advmon). As mentioned, we are 
> planning to offload the RSSI tracking to the controller as well, so there 
> will be changes to the corresponding MGMT commands.
> Thanks for your quick feedback!
>
> Regards,
> Miao
>
> On Wed, Sep 30, 2020 at 2:00 PM Von Dentz, Luiz  
> wrote:
>>
>> Hi Miao,
>>
>> I do recall seeing these at D-Bus level, or perhaps it was in use by 
>> bluetoothctl commands? Anyway since these are still experimental it should 
>> be fine to change them.
>> 
>> From: Miao-chen Chou 
>> Sent: Wednesday, September 30, 2020 12:51 PM
>> To: Holtmann, Marcel ; Von Dentz, Luiz 
>> 
>> Cc: Alain Michaud ; Yun-hao Chung 
>> ; Manish Mandlik ; Archie 
>> Pusaka 
>> Subject: Offload RSSI tracking to controller.
>>
>> Hi Luiz and Marcel,
>>
>> Going forward to 2020 Q4, we will be working on offloading the content 
>> filtering to the controllers based on controll's support of MSFT HCI 
>> extension. In the meantime, we are planning to change the existing MGMT 
>> commands of Adv monitoring to allow the offloading of RSSI tracking shortly. 
>> Here is a snippet of potential changes.
>>
>> +struct mgmt_adv_rssi_thresholds {
>> +   __s8 high_rssi_threshold;
>> +   u16 high_rssi_threshold_timeout;
>> +   __s8 low_rssi_threshold;
>> +   u16 high_rssi_threshold_timeout;
>> +} __packed;
>>
>> struct mgmt_cp_add_adv_patterns_monitor {
>> u8 pattern_count;
>> +struct mgmt_adv_rssi_thresholds rssi_thresholds;
>> struct mgmt_adv_pattern patterns[];
>> } __packed;
>>
>> Note that as suggested by you, the D-Bus Adv monitor API which accesses 
>> these MGMT commands is currently hidden behind the experimental flag, so 
>> they are still mutable. We'd like to hear your early feedback on changing 
>> the corresponding MGMT commands.
>>
>> Thanks,
>> Miao

Thanks,
Archie


[PATCH v1 5/5] Bluetooth: advmon offload MSFT handle filter enablement

2020-12-03 Thread Archie Pusaka
From: Archie Pusaka 

Implements the feature to disable/enable the filter used for
advertising monitor on MSFT controller, effectively have the same
effect as "remove all monitors" and "add all previously removed
monitors".

This feature would be needed when suspending, where we would not want
to get packets from anything outside the allowlist. Note that the
integration with the suspending part is not included in this patch.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

 net/bluetooth/msft.c | 67 
 net/bluetooth/msft.h |  6 
 2 files changed, 73 insertions(+)

diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index 7e33a85c3f1c..055cc5a260df 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -69,6 +69,17 @@ struct msft_rp_le_cancel_monitor_advertisement {
__u8 sub_opcode;
 } __packed;
 
+#define MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE 0x05
+struct msft_cp_le_set_advertisement_filter_enable {
+   __u8 sub_opcode;
+   __u8 enable;
+} __packed;
+
+struct msft_rp_le_set_advertisement_filter_enable {
+   __u8 status;
+   __u8 sub_opcode;
+} __packed;
+
 struct msft_monitor_advertisement_handle_data {
__u8  msft_handle;
__u16 mgmt_handle;
@@ -85,6 +96,7 @@ struct msft_data {
 
struct {
u8 reregistering:1;
+   u8 filter_enabled:1;
} flags;
 };
 
@@ -193,6 +205,7 @@ void msft_do_open(struct hci_dev *hdev)
 
if (msft_monitor_supported(hdev)) {
msft->flags.reregistering = true;
+   msft_set_filter_enable(hdev, true);
reregister_monitor_on_restart(hdev, 0);
}
 }
@@ -398,6 +411,40 @@ static void msft_le_cancel_monitor_advertisement_cb(struct 
hci_dev *hdev,
hci_remove_adv_monitor_complete(hdev, status);
 }
 
+static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev,
+  u8 status, u16 opcode,
+  struct sk_buff *skb)
+{
+   struct msft_cp_le_set_advertisement_filter_enable *cp;
+   struct msft_rp_le_set_advertisement_filter_enable *rp;
+   struct msft_data *msft = hdev->msft_data;
+
+   rp = (struct msft_rp_le_set_advertisement_filter_enable *)skb->data;
+   if (skb->len < sizeof(*rp))
+   return;
+
+   /* Error 0x0C would be returned if the filter enabled status is
+* already set to whatever we were trying to set.
+* Although the default state should be disabled, some controller set
+* the initial value to enabled. Because there is no way to know the
+* actual initial value before sending this command, here we also treat
+* error 0x0C as success.
+*/
+   if (status != 0x00 && status != 0x0C)
+   return;
+
+   hci_dev_lock(hdev);
+
+   cp = hci_sent_cmd_data(hdev, hdev->msft_opcode);
+   msft->flags.filter_enabled = cp->enable;
+
+   if (status == 0x0C)
+   bt_dev_warn(hdev, "MSFT filter_enable is already %s",
+   cp->enable ? "on" : "off");
+
+   hci_dev_unlock(hdev);
+}
+
 static bool msft_monitor_rssi_valid(struct adv_monitor *monitor)
 {
struct adv_rssi_thresholds *r = >rssi;
@@ -534,3 +581,23 @@ int msft_remove_monitor(struct hci_dev *hdev, struct 
adv_monitor *monitor,
 
return err;
 }
+
+int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
+{
+   struct msft_cp_le_set_advertisement_filter_enable cp;
+   struct hci_request req;
+   struct msft_data *msft = hdev->msft_data;
+   int err;
+
+   if (!msft)
+   return -EOPNOTSUPP;
+
+   cp.sub_opcode = MSFT_OP_LE_SET_ADVERTISEMENT_FILTER_ENABLE;
+   cp.enable = enable;
+
+   hci_req_init(, hdev);
+   hci_req_add(, hdev->msft_opcode, sizeof(cp), );
+   err = hci_req_run_skb(, msft_le_set_advertisement_filter_enable_cb);
+
+   return err;
+}
diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
index 9f9a11f90b0c..44bee705c16d 100644
--- a/net/bluetooth/msft.h
+++ b/net/bluetooth/msft.h
@@ -20,6 +20,7 @@ __u64 msft_get_features(struct hci_dev *hdev);
 int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor 
*monitor);
 int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
u16 handle);
+int msft_set_filter_enable(struct hci_dev *hdev, bool enable);
 
 #else
 
@@ -45,4 +46,9 @@ static inline bool msft_remove_monitor(struct hci_dev *hdev,
return -EOPNOTSUPP;
 }
 
+static inline int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
+{
+   return -EOPNOTSUPP;
+}
+
 #endif
-- 
2.29.2.454.gaff20da3a2-goog



[PATCH v1 2/5] Bluetooth: advmon offload MSFT add monitor

2020-12-03 Thread Archie Pusaka
From: Archie Pusaka 

Enables advertising monitor offloading to the controller, if MSFT
extension is supported. The kernel won't adjust the monitor parameters
to match what the controller supports - that is the user space's
responsibility.

This patch only manages the addition of monitors. Monitor removal is
going to be handled by another patch.

Signed-off-by: Archie Pusaka 
Reviewed-by: Manish Mandlik 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

 include/net/bluetooth/hci_core.h |  17 ++-
 net/bluetooth/hci_core.c |  54 +++--
 net/bluetooth/mgmt.c | 150 +++
 net/bluetooth/msft.c | 201 ++-
 net/bluetooth/msft.h |  12 ++
 5 files changed, 369 insertions(+), 65 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 42d446417817..275061a1b670 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -257,13 +257,20 @@ struct adv_rssi_thresholds {
 struct adv_monitor {
struct list_head patterns;
struct adv_rssi_thresholds rssi;
-   boolactive;
__u16   handle;
+
+   enum {
+   ADV_MONITOR_STATE_NOT_REGISTERED,
+   ADV_MONITOR_STATE_REGISTERED,
+   ADV_MONITOR_STATE_OFFLOADED
+   } state;
 };
 
 #define HCI_MIN_ADV_MONITOR_HANDLE 1
-#define HCI_MAX_ADV_MONITOR_NUM_HANDLES32
+#define HCI_MAX_ADV_MONITOR_NUM_HANDLES32
 #define HCI_MAX_ADV_MONITOR_NUM_PATTERNS   16
+#define HCI_ADV_MONITOR_EXT_NONE   1
+#define HCI_ADV_MONITOR_EXT_MSFT   2
 
 #define HCI_MAX_SHORT_NAME_LENGTH  10
 
@@ -1305,9 +1312,12 @@ void hci_adv_instances_set_rpa_expired(struct hci_dev 
*hdev, bool rpa_expired);
 
 void hci_adv_monitors_clear(struct hci_dev *hdev);
 void hci_free_adv_monitor(struct adv_monitor *monitor);
-int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
+int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
+   int *err);
 int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle);
 bool hci_is_adv_monitoring(struct hci_dev *hdev);
+int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev);
 
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
 
@@ -1783,6 +1793,7 @@ void mgmt_advertising_added(struct sock *sk, struct 
hci_dev *hdev,
 void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
  u8 instance);
 int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
+int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
 
 u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
  u16 to_multiplier);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index c4aa2cbb9269..7f70812dde15 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3031,27 +3031,55 @@ void hci_free_adv_monitor(struct adv_monitor *monitor)
kfree(monitor);
 }
 
-/* This function requires the caller holds hdev->lock */
-int hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
+int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)
+{
+   return mgmt_add_adv_patterns_monitor_complete(hdev, status);
+}
+
+/* Assigns handle to a monitor, and if offloading is supported and power is on,
+ * also attempts to forward the request to the controller.
+ * Returns true if request is forwarded (result is pending), false otherwise.
+ * This function requires the caller holds hdev->lock.
+ */
+bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
+int *err)
 {
int min, max, handle;
 
-   if (!monitor)
-   return -EINVAL;
+   *err = 0;
+
+   if (!monitor) {
+   *err = -EINVAL;
+   return false;
+   }
 
min = HCI_MIN_ADV_MONITOR_HANDLE;
max = HCI_MIN_ADV_MONITOR_HANDLE + HCI_MAX_ADV_MONITOR_NUM_HANDLES;
handle = idr_alloc(>adv_monitors_idr, monitor, min, max,
   GFP_KERNEL);
-   if (handle < 0)
-   return handle;
+   if (handle < 0) {
+   *err = handle;
+   return false;
+   }
 
-   hdev->adv_monitors_cnt++;
monitor->handle = handle;
 
-   hci_update_background_scan(hdev);
+   if (!hdev_is_powered(hdev))
+   return false;
 
-   return 0;
+   switch (hci_get_adv_monitor_offload_ext(hdev)) {
+   case HCI_ADV_MONITOR_EXT_NONE:
+   hci_update_background_scan(hdev);
+   BT_DBG("%s add monitor status %d", hdev->name, *err);
+   /* Message was not forw

[PATCH v1 4/5] Bluetooth: advmon offload MSFT handle controller reset

2020-12-03 Thread Archie Pusaka
From: Archie Pusaka 

When the controller is powered off, the registered advertising monitor
is removed from the controller. This patch handles the re-registration
of those monitors when the power is on.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

 net/bluetooth/msft.c | 79 +---
 1 file changed, 74 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index f5aa0e3b1b9b..7e33a85c3f1c 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -82,8 +82,15 @@ struct msft_data {
struct list_head handle_map;
__u16 pending_add_handle;
__u16 pending_remove_handle;
+
+   struct {
+   u8 reregistering:1;
+   } flags;
 };
 
+static int __msft_add_monitor_pattern(struct hci_dev *hdev,
+ struct adv_monitor *monitor);
+
 bool msft_monitor_supported(struct hci_dev *hdev)
 {
return !!(msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR);
@@ -134,6 +141,35 @@ static bool read_supported_features(struct hci_dev *hdev,
return false;
 }
 
+/* This function requires the caller holds hdev->lock */
+static void reregister_monitor_on_restart(struct hci_dev *hdev, int handle)
+{
+   struct adv_monitor *monitor;
+   struct msft_data *msft = hdev->msft_data;
+   int err;
+
+   while (1) {
+   monitor = idr_get_next(>adv_monitors_idr, );
+   if (!monitor) {
+   /* All monitors have been reregistered */
+   msft->flags.reregistering = false;
+   hci_update_background_scan(hdev);
+   return;
+   }
+
+   msft->pending_add_handle = (u16)handle;
+   err = __msft_add_monitor_pattern(hdev, monitor);
+
+   /* If success, we return and wait for monitor added callback */
+   if (!err)
+   return;
+
+   /* Otherwise remove the monitor and keep registering */
+   hci_free_adv_monitor(hdev, monitor);
+   handle++;
+   }
+}
+
 void msft_do_open(struct hci_dev *hdev)
 {
struct msft_data *msft;
@@ -154,12 +190,18 @@ void msft_do_open(struct hci_dev *hdev)
 
INIT_LIST_HEAD(>handle_map);
hdev->msft_data = msft;
+
+   if (msft_monitor_supported(hdev)) {
+   msft->flags.reregistering = true;
+   reregister_monitor_on_restart(hdev, 0);
+   }
 }
 
 void msft_do_close(struct hci_dev *hdev)
 {
struct msft_data *msft = hdev->msft_data;
struct msft_monitor_advertisement_handle_data *handle_data, *tmp;
+   struct adv_monitor *monitor;
 
if (!msft)
return;
@@ -169,6 +211,12 @@ void msft_do_close(struct hci_dev *hdev)
hdev->msft_data = NULL;
 
list_for_each_entry_safe(handle_data, tmp, >handle_map, list) {
+   monitor = idr_find(>adv_monitors_idr,
+  handle_data->mgmt_handle);
+
+   if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED)
+   monitor->state = ADV_MONITOR_STATE_REGISTERED;
+
list_del(_data->list);
kfree(handle_data);
}
@@ -282,9 +330,15 @@ static void msft_le_monitor_advertisement_cb(struct 
hci_dev *hdev,
if (status && monitor)
hci_free_adv_monitor(hdev, monitor);
 
+   /* If in restart/reregister sequence, keep registering. */
+   if (msft->flags.reregistering)
+   reregister_monitor_on_restart(hdev,
+ msft->pending_add_handle + 1);
+
hci_dev_unlock(hdev);
 
-   hci_add_adv_patterns_monitor_complete(hdev, status);
+   if (!msft->flags.reregistering)
+   hci_add_adv_patterns_monitor_complete(hdev, status);
 }
 
 static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
@@ -374,7 +428,8 @@ static bool msft_monitor_pattern_valid(struct adv_monitor 
*monitor)
 }
 
 /* This function requires the caller holds hdev->lock */
-int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor)
+static int __msft_add_monitor_pattern(struct hci_dev *hdev,
+ struct adv_monitor *monitor)
 {
struct msft_cp_le_monitor_advertisement *cp;
struct msft_le_monitor_advertisement_pattern_data *pattern_data;
@@ -387,9 +442,6 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct 
adv_monitor *monitor)
u8 pattern_count = 0;
int err = 0;
 
-   if (!msft)
-   return -EOPNOTSUPP;
-
if (!msft_monitor_pattern_valid(monitor))
return -EINVAL;
 
@@ -434,6 +486,20 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct 
adv_monitor *monitor)

[PATCH v1 3/5] Bluetooth: advmon offload MSFT remove monitor

2020-12-03 Thread Archie Pusaka
From: Archie Pusaka 

Implements the monitor removal functionality for advertising monitor
offloading to MSFT controllers. Supply handle = 0 to remove all
monitors.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

 include/net/bluetooth/hci_core.h |   8 +-
 net/bluetooth/hci_core.c | 119 +++--
 net/bluetooth/mgmt.c | 109 +-
 net/bluetooth/msft.c | 127 ++-
 net/bluetooth/msft.h |   9 +++
 5 files changed, 322 insertions(+), 50 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 275061a1b670..0a211cd52fdb 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1311,11 +1311,13 @@ int hci_remove_adv_instance(struct hci_dev *hdev, u8 
instance);
 void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired);
 
 void hci_adv_monitors_clear(struct hci_dev *hdev);
-void hci_free_adv_monitor(struct adv_monitor *monitor);
+void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
 int hci_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
 bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
int *err);
-int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle);
+bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err);
+bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err);
 bool hci_is_adv_monitoring(struct hci_dev *hdev);
 int hci_get_adv_monitor_offload_ext(struct hci_dev *hdev);
 
@@ -1792,8 +1794,10 @@ void mgmt_advertising_added(struct sock *sk, struct 
hci_dev *hdev,
u8 instance);
 void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
  u8 instance);
+void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle);
 int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
 int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
+int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
 
 u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
  u16 to_multiplier);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 7f70812dde15..70bb2a11d9b1 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3012,12 +3012,15 @@ void hci_adv_monitors_clear(struct hci_dev *hdev)
int handle;
 
idr_for_each_entry(>adv_monitors_idr, monitor, handle)
-   hci_free_adv_monitor(monitor);
+   hci_free_adv_monitor(hdev, monitor);
 
idr_destroy(>adv_monitors_idr);
 }
 
-void hci_free_adv_monitor(struct adv_monitor *monitor)
+/* Frees the monitor structure and do some bookkeepings.
+ * This function requires the caller holds hdev->lock.
+ */
+void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
 {
struct adv_pattern *pattern;
struct adv_pattern *tmp;
@@ -3025,8 +3028,18 @@ void hci_free_adv_monitor(struct adv_monitor *monitor)
if (!monitor)
return;
 
-   list_for_each_entry_safe(pattern, tmp, >patterns, list)
+   list_for_each_entry_safe(pattern, tmp, >patterns, list) {
+   list_del(>list);
kfree(pattern);
+   }
+
+   if (monitor->handle)
+   idr_remove(>adv_monitors_idr, monitor->handle);
+
+   if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED) {
+   hdev->adv_monitors_cnt--;
+   mgmt_adv_monitor_removed(hdev, monitor->handle);
+   }
 
kfree(monitor);
 }
@@ -3036,6 +3049,11 @@ int hci_add_adv_patterns_monitor_complete(struct hci_dev 
*hdev, u8 status)
return mgmt_add_adv_patterns_monitor_complete(hdev, status);
 }
 
+int hci_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
+{
+   return mgmt_remove_adv_monitor_complete(hdev, status);
+}
+
 /* Assigns handle to a monitor, and if offloading is supported and power is on,
  * also attempts to forward the request to the controller.
  * Returns true if request is forwarded (result is pending), false otherwise.
@@ -3082,39 +3100,94 @@ bool hci_add_adv_monitor(struct hci_dev *hdev, struct 
adv_monitor *monitor,
return (*err == 0);
 }
 
-static int free_adv_monitor(int id, void *ptr, void *data)
+/* Attempts to tell the controller and free the monitor. If somehow the
+ * controller doesn't have a corresponding handle, remove anyway.
+ * Returns true if request is forwarded (result is pending), false otherwise.
+ * This function requires the caller holds hdev->lock.
+ */
+static bool hci_remove_adv_monitor(struct hci_dev *hdev,
+  

[PATCH v1 1/5] Bluetooth: advmon offload MSFT add rssi support

2020-12-03 Thread Archie Pusaka
From: Archie Pusaka 

MSFT needs rssi parameter for monitoring advertisement packet,
therefore we should supply them from mgmt.

Signed-off-by: Archie Pusaka 
Reviewed-by: Miao-chen Chou 
Reviewed-by: Yun-Hao Chung 

---

 include/net/bluetooth/hci_core.h | 9 +
 include/net/bluetooth/mgmt.h | 9 +
 net/bluetooth/mgmt.c | 8 
 3 files changed, 26 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 9873e1c8cd16..42d446417817 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -246,8 +246,17 @@ struct adv_pattern {
__u8 value[HCI_MAX_AD_LENGTH];
 };
 
+struct adv_rssi_thresholds {
+   __s8 low_threshold;
+   __s8 high_threshold;
+   __u16 low_threshold_timeout;
+   __u16 high_threshold_timeout;
+   __u8 sampling_period;
+};
+
 struct adv_monitor {
struct list_head patterns;
+   struct adv_rssi_thresholds rssi;
boolactive;
__u16   handle;
 };
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index d8367850e8cd..dc534837be0e 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -763,9 +763,18 @@ struct mgmt_adv_pattern {
__u8 value[31];
 } __packed;
 
+struct mgmt_adv_rssi_thresholds {
+   __s8 high_threshold;
+   __le16 high_threshold_timeout;
+   __s8 low_threshold;
+   __le16 low_threshold_timeout;
+   __u8 sampling_period;
+} __packed;
+
 #define MGMT_OP_ADD_ADV_PATTERNS_MONITOR   0x0052
 struct mgmt_cp_add_adv_patterns_monitor {
__u8 pattern_count;
+   struct mgmt_adv_rssi_thresholds rssi;
struct mgmt_adv_pattern patterns[];
 } __packed;
 #define MGMT_ADD_ADV_PATTERNS_MONITOR_SIZE 1
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 3dfed4efa078..5f0f03dcd81d 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4237,6 +4237,14 @@ static int add_adv_patterns_monitor(struct sock *sk, 
struct hci_dev *hdev,
INIT_LIST_HEAD(>patterns);
m->active = false;
 
+   m->rssi.low_threshold = cp->rssi.low_threshold;
+   m->rssi.low_threshold_timeout =
+   __le16_to_cpu(cp->rssi.low_threshold_timeout);
+   m->rssi.high_threshold = cp->rssi.high_threshold;
+   m->rssi.high_threshold_timeout =
+   __le16_to_cpu(cp->rssi.high_threshold_timeout);
+   m->rssi.sampling_period = cp->rssi.sampling_period;
+
for (i = 0; i < cp->pattern_count; i++) {
if (++mp_cnt > HCI_MAX_ADV_MONITOR_NUM_PATTERNS) {
err = mgmt_cmd_status(sk, hdev->id,
-- 
2.29.2.454.gaff20da3a2-goog



[PATCH v1 0/5] MSFT offloading support for advertisement monitor

2020-12-03 Thread Archie Pusaka
From: Archie Pusaka 

Hi linux-bluetooth,

This series of patches manages the hardware offloading part of MSFT
extension API. The full documentation can be accessed by this link:
https://docs.microsoft.com/en-us/windows-hardware/drivers/bluetooth/microsoft-defined-bluetooth-hci-commands-and-events

Only four of the HCI commands are planned to be implemented:
HCI_VS_MSFT_Read_Supported_Features (implemented in previous patch),
HCI_VS_MSFT_LE_Monitor_Advertisement,
HCI_VS_MSFT_LE_Cancel_Monitor_Advertisement, and
HCI_VS_MSFT_LE_Set_Advertisement_Filter_Enable.
These are the commands which would be used for advertisement monitor
feature. Only if the controller supports the MSFT extension would
these commands be sent. Otherwise, software-based monitoring would be
performed in the user space instead.

Thanks in advance for your feedback!

Archie


Archie Pusaka (5):
  Bluetooth: advmon offload MSFT add rssi support
  Bluetooth: advmon offload MSFT add monitor
  Bluetooth: advmon offload MSFT remove monitor
  Bluetooth: advmon offload MSFT handle controller reset
  Bluetooth: advmon offload MSFT handle filter enablement

 include/net/bluetooth/hci_core.h |  34 ++-
 include/net/bluetooth/mgmt.h |   9 +
 net/bluetooth/hci_core.c | 173 +---
 net/bluetooth/mgmt.c | 263 +-
 net/bluetooth/msft.c | 456 ++-
 net/bluetooth/msft.h |  27 ++
 6 files changed, 853 insertions(+), 109 deletions(-)

-- 
2.29.2.454.gaff20da3a2-goog



[PATCH v2] Bluetooth: Enforce key size of 16 bytes on FIPS level

2020-11-10 Thread Archie Pusaka
From: Archie Pusaka 

According to the spec Ver 5.2, Vol 3, Part C, Sec 5.2.2.8:
Device in security mode 4 level 4 shall enforce:
128-bit equivalent strength for link and encryption keys required
using FIPS approved algorithms (E0 not allowed, SAFER+ not allowed,
and P-192 not allowed; encryption key not shortened)

This patch rejects connection with key size below 16 for FIPS
level services.

Signed-off-by: Archie Pusaka 
Reviewed-by: Alain Michaud 

---

Sorry for the long delay. This patch fell out of my radar.

Changes in v2:
* Add comment on enforcing 16 bytes key size

 net/bluetooth/l2cap_core.c | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 1ab27b90ddcb..5817f5c2ec18 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1515,8 +1515,14 @@ static bool l2cap_check_enc_key_size(struct hci_conn 
*hcon)
 * that have no key size requirements. Ensure that the link is
 * actually encrypted before enforcing a key size.
 */
+   int min_key_size = hcon->hdev->min_enc_key_size;
+
+   /* On FIPS security level, key size must be 16 bytes */
+   if (hcon->sec_level == BT_SECURITY_FIPS)
+   min_key_size = 16;
+
return (!test_bit(HCI_CONN_ENCRYPT, >flags) ||
-   hcon->enc_key_size >= hcon->hdev->min_enc_key_size);
+   hcon->enc_key_size >= min_key_size);
 }
 
 static void l2cap_do_start(struct l2cap_chan *chan)
-- 
2.29.2.299.gdc1121823c-goog



Re: [PATCH v3] Bluetooth: Check for encryption key size on connect

2020-10-04 Thread Archie Pusaka
[Re-sending in plain text]
Hi Marcel,

I tried Alex's patch and it works for me as well.

Thanks,
Archie


On Thu, 1 Oct 2020 at 15:14, Marcel Holtmann  wrote:
>
> Hi Archie,
>
> >>>>>>>>> When receiving connection, we only check whether the link has been
> >>>>>>>>> encrypted, but not the encryption key size of the link.
> >>>>>>>>>
> >>>>>>>>> This patch adds check for encryption key size, and reject L2CAP
> >>>>>>>>> connection which size is below the specified threshold (default 7)
> >>>>>>>>> with security block.
> >>>>>>>>>
> >>>>>>>>> Here is some btmon trace.
> >>>>>>>>> @ MGMT Event: New Link Key (0x0009) plen 26{0x0001} [hci0] 
> >>>>>>>>> 5.847722
> >>>>>>>>>Store hint: No (0x00)
> >>>>>>>>>BR/EDR Address: 38:00:25:F7:F1:B0 (OUI 38-00-25)
> >>>>>>>>>Key type: Unauthenticated Combination key from P-192 (0x04)
> >>>>>>>>>Link key: 7bf2f68c81305d63a6b0ee2c5a7a34bc
> >>>>>>>>>PIN length: 0
> >>>>>>>>>> HCI Event: Encryption Change (0x08) plen 4#29 [hci0] 
> >>>>>>>>>> 5.871537
> >>>>>>>>>Status: Success (0x00)
> >>>>>>>>>Handle: 256
> >>>>>>>>>Encryption: Enabled with E0 (0x01)
> >>>>>>>>> < HCI Command: Read Encryp... (0x05|0x0008) plen 2  #30 [hci0] 
> >>>>>>>>> 5.871609
> >>>>>>>>>Handle: 256
> >>>>>>>>>> HCI Event: Command Complete (0x0e) plen 7 #31 [hci0] 
> >>>>>>>>>> 5.872524
> >>>>>>>>>  Read Encryption Key Size (0x05|0x0008) ncmd 1
> >>>>>>>>>Status: Success (0x00)
> >>>>>>>>>Handle: 256
> >>>>>>>>>Key size: 3
> >>>>>>>>>
> >>>>>>>>> // WITHOUT PATCH //
> >>>>>>>>>> ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 
> >>>>>>>>>> 5.895023
> >>>>>>>>>  L2CAP: Connection Request (0x02) ident 3 len 4
> >>>>>>>>>PSM: 4097 (0x1001)
> >>>>>>>>>Source CID: 64
> >>>>>>>>> < ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 
> >>>>>>>>> 5.895213
> >>>>>>>>>  L2CAP: Connection Response (0x03) ident 3 len 8
> >>>>>>>>>Destination CID: 64
> >>>>>>>>>Source CID: 64
> >>>>>>>>>Result: Connection successful (0x)
> >>>>>>>>>Status: No further information available (0x)
> >>>>>>>>>
> >>>>>>>>> // WITH PATCH //
> >>>>>>>>>> ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 
> >>>>>>>>>> 4.887024
> >>>>>>>>>  L2CAP: Connection Request (0x02) ident 3 len 4
> >>>>>>>>>PSM: 4097 (0x1001)
> >>>>>>>>>Source CID: 64
> >>>>>>>>> < ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 
> >>>>>>>>> 4.887127
> >>>>>>>>>  L2CAP: Connection Response (0x03) ident 3 len 8
> >>>>>>>>>Destination CID: 0
> >>>>>>>>>Source CID: 64
> >>>>>>>>>Result: Connection refused - security block (0x0003)
> >>>>>>>>>Status: No further information available (0x)
> >>>>>>>>>
> >>>>>>>>> Signed-off-by: Archie Pusaka 
> >>>>>>>>>
> >>>>>>>>> ---
> >>>>>>>>>
> >>>>>>>>> Changes in v3:
> >>>>>>>>> * Move the check to hci_conn_check_link_mode()
> >>>>>>>>>
> >>>>>>>>> Cha

Re: [PATCH v3] Bluetooth: Check for encryption key size on connect

2020-09-29 Thread Archie Pusaka
Hi Marcel,

On Tue, 29 Sep 2020 at 14:21, Marcel Holtmann  wrote:
>
> Hi Archie,
>
> >>>>>>> When receiving connection, we only check whether the link has been
> >>>>>>> encrypted, but not the encryption key size of the link.
> >>>>>>>
> >>>>>>> This patch adds check for encryption key size, and reject L2CAP
> >>>>>>> connection which size is below the specified threshold (default 7)
> >>>>>>> with security block.
> >>>>>>>
> >>>>>>> Here is some btmon trace.
> >>>>>>> @ MGMT Event: New Link Key (0x0009) plen 26{0x0001} [hci0] 
> >>>>>>> 5.847722
> >>>>>>> Store hint: No (0x00)
> >>>>>>> BR/EDR Address: 38:00:25:F7:F1:B0 (OUI 38-00-25)
> >>>>>>> Key type: Unauthenticated Combination key from P-192 (0x04)
> >>>>>>> Link key: 7bf2f68c81305d63a6b0ee2c5a7a34bc
> >>>>>>> PIN length: 0
> >>>>>>>> HCI Event: Encryption Change (0x08) plen 4#29 [hci0] 5.871537
> >>>>>>> Status: Success (0x00)
> >>>>>>> Handle: 256
> >>>>>>> Encryption: Enabled with E0 (0x01)
> >>>>>>> < HCI Command: Read Encryp... (0x05|0x0008) plen 2  #30 [hci0] 
> >>>>>>> 5.871609
> >>>>>>> Handle: 256
> >>>>>>>> HCI Event: Command Complete (0x0e) plen 7 #31 [hci0] 5.872524
> >>>>>>>   Read Encryption Key Size (0x05|0x0008) ncmd 1
> >>>>>>> Status: Success (0x00)
> >>>>>>> Handle: 256
> >>>>>>> Key size: 3
> >>>>>>>
> >>>>>>> // WITHOUT PATCH //
> >>>>>>>> ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 5.895023
> >>>>>>>   L2CAP: Connection Request (0x02) ident 3 len 4
> >>>>>>> PSM: 4097 (0x1001)
> >>>>>>> Source CID: 64
> >>>>>>> < ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 
> >>>>>>> 5.895213
> >>>>>>>   L2CAP: Connection Response (0x03) ident 3 len 8
> >>>>>>> Destination CID: 64
> >>>>>>> Source CID: 64
> >>>>>>> Result: Connection successful (0x)
> >>>>>>> Status: No further information available (0x)
> >>>>>>>
> >>>>>>> // WITH PATCH //
> >>>>>>>> ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 4.887024
> >>>>>>>   L2CAP: Connection Request (0x02) ident 3 len 4
> >>>>>>> PSM: 4097 (0x1001)
> >>>>>>> Source CID: 64
> >>>>>>> < ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 
> >>>>>>> 4.887127
> >>>>>>>   L2CAP: Connection Response (0x03) ident 3 len 8
> >>>>>>> Destination CID: 0
> >>>>>>> Source CID: 64
> >>>>>>> Result: Connection refused - security block (0x0003)
> >>>>>>> Status: No further information available (0x)
> >>>>>>>
> >>>>>>> Signed-off-by: Archie Pusaka 
> >>>>>>>
> >>>>>>> ---
> >>>>>>>
> >>>>>>> Changes in v3:
> >>>>>>> * Move the check to hci_conn_check_link_mode()
> >>>>>>>
> >>>>>>> Changes in v2:
> >>>>>>> * Add btmon trace to the commit message
> >>>>>>>
> >>>>>>> net/bluetooth/hci_conn.c | 4 
> >>>>>>> 1 file changed, 4 insertions(+)
> >>>>>>>
> >>>>>>> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> >>>>>>> index 9832f8445d43..89085fac797c 100644
> >>>>>>> --- a/net/bluetooth/hci_conn.c
> >>>>>>> +++ b/net/bluetooth/hci_conn.c
> >>>>>>> @@ -1348,6 +1348,10 @@ int hci_conn_check_link_mode(struct hci_conn 
> >>>>>>> *conn)
> >>>>&

Re: [PATCH v3] Bluetooth: Check for encryption key size on connect

2020-09-28 Thread Archie Pusaka
Hi Marcel,

On Tue, 29 Sep 2020 at 00:43, Marcel Holtmann  wrote:
>
> Hi Archie,
>
> >>>>> When receiving connection, we only check whether the link has been
> >>>>> encrypted, but not the encryption key size of the link.
> >>>>>
> >>>>> This patch adds check for encryption key size, and reject L2CAP
> >>>>> connection which size is below the specified threshold (default 7)
> >>>>> with security block.
> >>>>>
> >>>>> Here is some btmon trace.
> >>>>> @ MGMT Event: New Link Key (0x0009) plen 26{0x0001} [hci0] 5.847722
> >>>>>  Store hint: No (0x00)
> >>>>>  BR/EDR Address: 38:00:25:F7:F1:B0 (OUI 38-00-25)
> >>>>>  Key type: Unauthenticated Combination key from P-192 (0x04)
> >>>>>  Link key: 7bf2f68c81305d63a6b0ee2c5a7a34bc
> >>>>>  PIN length: 0
> >>>>>> HCI Event: Encryption Change (0x08) plen 4#29 [hci0] 5.871537
> >>>>>  Status: Success (0x00)
> >>>>>  Handle: 256
> >>>>>  Encryption: Enabled with E0 (0x01)
> >>>>> < HCI Command: Read Encryp... (0x05|0x0008) plen 2  #30 [hci0] 5.871609
> >>>>>  Handle: 256
> >>>>>> HCI Event: Command Complete (0x0e) plen 7 #31 [hci0] 5.872524
> >>>>>Read Encryption Key Size (0x05|0x0008) ncmd 1
> >>>>>  Status: Success (0x00)
> >>>>>  Handle: 256
> >>>>>  Key size: 3
> >>>>>
> >>>>> // WITHOUT PATCH //
> >>>>>> ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 5.895023
> >>>>>L2CAP: Connection Request (0x02) ident 3 len 4
> >>>>>  PSM: 4097 (0x1001)
> >>>>>  Source CID: 64
> >>>>> < ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 5.895213
> >>>>>L2CAP: Connection Response (0x03) ident 3 len 8
> >>>>>  Destination CID: 64
> >>>>>  Source CID: 64
> >>>>>  Result: Connection successful (0x0000)
> >>>>>  Status: No further information available (0x)
> >>>>>
> >>>>> // WITH PATCH //
> >>>>>> ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 4.887024
> >>>>>L2CAP: Connection Request (0x02) ident 3 len 4
> >>>>>  PSM: 4097 (0x1001)
> >>>>>  Source CID: 64
> >>>>> < ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 4.887127
> >>>>>L2CAP: Connection Response (0x03) ident 3 len 8
> >>>>>  Destination CID: 0
> >>>>>  Source CID: 64
> >>>>>  Result: Connection refused - security block (0x0003)
> >>>>>  Status: No further information available (0x)
> >>>>>
> >>>>> Signed-off-by: Archie Pusaka 
> >>>>>
> >>>>> ---
> >>>>>
> >>>>> Changes in v3:
> >>>>> * Move the check to hci_conn_check_link_mode()
> >>>>>
> >>>>> Changes in v2:
> >>>>> * Add btmon trace to the commit message
> >>>>>
> >>>>> net/bluetooth/hci_conn.c | 4 
> >>>>> 1 file changed, 4 insertions(+)
> >>>>>
> >>>>> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> >>>>> index 9832f8445d43..89085fac797c 100644
> >>>>> --- a/net/bluetooth/hci_conn.c
> >>>>> +++ b/net/bluetooth/hci_conn.c
> >>>>> @@ -1348,6 +1348,10 @@ int hci_conn_check_link_mode(struct hci_conn 
> >>>>> *conn)
> >>>>> !test_bit(HCI_CONN_ENCRYPT, >flags))
> >>>>> return 0;
> >>>>>
> >>>>> + if (test_bit(HCI_CONN_ENCRYPT, >flags) &&
> >>>>> + conn->enc_key_size < conn->hdev->min_enc_key_size)
> >>>>> + return 0;
> >>>>> +
> >>>>> return 1;
> >>>>> }
> >>>>
> >>>> I am a bit concerned since we had that check and I on purpose moved it. 
> >>>> See commit 693cd8ce3f88 for the change where I removed and commit 
>

Re: [PATCH v3] Bluetooth: Check for encryption key size on connect

2020-09-28 Thread Archie Pusaka
Hi Marcel,

On Sun, 27 Sep 2020 at 20:09, Marcel Holtmann  wrote:
>
> Hi Archie,
>
> >>> When receiving connection, we only check whether the link has been
> >>> encrypted, but not the encryption key size of the link.
> >>>
> >>> This patch adds check for encryption key size, and reject L2CAP
> >>> connection which size is below the specified threshold (default 7)
> >>> with security block.
> >>>
> >>> Here is some btmon trace.
> >>> @ MGMT Event: New Link Key (0x0009) plen 26{0x0001} [hci0] 5.847722
> >>>   Store hint: No (0x00)
> >>>   BR/EDR Address: 38:00:25:F7:F1:B0 (OUI 38-00-25)
> >>>   Key type: Unauthenticated Combination key from P-192 (0x04)
> >>>   Link key: 7bf2f68c81305d63a6b0ee2c5a7a34bc
> >>>   PIN length: 0
> >>>> HCI Event: Encryption Change (0x08) plen 4#29 [hci0] 5.871537
> >>>   Status: Success (0x00)
> >>>   Handle: 256
> >>>   Encryption: Enabled with E0 (0x01)
> >>> < HCI Command: Read Encryp... (0x05|0x0008) plen 2  #30 [hci0] 5.871609
> >>>   Handle: 256
> >>>> HCI Event: Command Complete (0x0e) plen 7 #31 [hci0] 5.872524
> >>> Read Encryption Key Size (0x05|0x0008) ncmd 1
> >>>   Status: Success (0x00)
> >>>   Handle: 256
> >>>   Key size: 3
> >>>
> >>> // WITHOUT PATCH //
> >>>> ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 5.895023
> >>> L2CAP: Connection Request (0x02) ident 3 len 4
> >>>   PSM: 4097 (0x1001)
> >>>   Source CID: 64
> >>> < ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 5.895213
> >>> L2CAP: Connection Response (0x03) ident 3 len 8
> >>>   Destination CID: 64
> >>>   Source CID: 64
> >>>   Result: Connection successful (0x)
> >>>   Status: No further information available (0x)
> >>>
> >>> // WITH PATCH //
> >>>> ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 4.887024
> >>> L2CAP: Connection Request (0x02) ident 3 len 4
> >>>   PSM: 4097 (0x1001)
> >>>   Source CID: 64
> >>> < ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 4.887127
> >>> L2CAP: Connection Response (0x03) ident 3 len 8
> >>>   Destination CID: 0
> >>>   Source CID: 64
> >>>   Result: Connection refused - security block (0x0003)
> >>>   Status: No further information available (0x)
> >>>
> >>> Signed-off-by: Archie Pusaka 
> >>>
> >>> ---
> >>>
> >>> Changes in v3:
> >>> * Move the check to hci_conn_check_link_mode()
> >>>
> >>> Changes in v2:
> >>> * Add btmon trace to the commit message
> >>>
> >>> net/bluetooth/hci_conn.c | 4 
> >>> 1 file changed, 4 insertions(+)
> >>>
> >>> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> >>> index 9832f8445d43..89085fac797c 100644
> >>> --- a/net/bluetooth/hci_conn.c
> >>> +++ b/net/bluetooth/hci_conn.c
> >>> @@ -1348,6 +1348,10 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
> >>>  !test_bit(HCI_CONN_ENCRYPT, >flags))
> >>>  return 0;
> >>>
> >>> + if (test_bit(HCI_CONN_ENCRYPT, >flags) &&
> >>> + conn->enc_key_size < conn->hdev->min_enc_key_size)
> >>> + return 0;
> >>> +
> >>>  return 1;
> >>> }
> >>
> >> I am a bit concerned since we had that check and I on purpose moved it. 
> >> See commit 693cd8ce3f88 for the change where I removed and commit 
> >> d5bb334a8e17 where I initially added it.
> >>
> >> Naively adding the check in that location caused a major regression with 
> >> Bluetooth 2.0 devices. This makes me a bit reluctant to re-add it here 
> >> since I restructured the whole change to check the key size a different 
> >> location.
> >
> > I have tried this patch (both v2 and v3) to connect with a Bluetooth
> > 2.0 device, it doesn't have any connection problem.
> > I suppose because in the original patch (d5bb334a8e17), there is no
> > check for the HCI_CONN_ENCRYPT flag.
>

Re: [PATCH v3] Bluetooth: Check for encryption key size on connect

2020-09-26 Thread Archie Pusaka
Hi Marcel,

On Sat, 26 Sep 2020 at 00:37, Marcel Holtmann  wrote:
>
> Hi Archie,
>
> > When receiving connection, we only check whether the link has been
> > encrypted, but not the encryption key size of the link.
> >
> > This patch adds check for encryption key size, and reject L2CAP
> > connection which size is below the specified threshold (default 7)
> > with security block.
> >
> > Here is some btmon trace.
> > @ MGMT Event: New Link Key (0x0009) plen 26{0x0001} [hci0] 5.847722
> >Store hint: No (0x00)
> >BR/EDR Address: 38:00:25:F7:F1:B0 (OUI 38-00-25)
> >Key type: Unauthenticated Combination key from P-192 (0x04)
> >Link key: 7bf2f68c81305d63a6b0ee2c5a7a34bc
> >PIN length: 0
> >> HCI Event: Encryption Change (0x08) plen 4#29 [hci0] 5.871537
> >Status: Success (0x00)
> >Handle: 256
> >Encryption: Enabled with E0 (0x01)
> > < HCI Command: Read Encryp... (0x05|0x0008) plen 2  #30 [hci0] 5.871609
> >Handle: 256
> >> HCI Event: Command Complete (0x0e) plen 7 #31 [hci0] 5.872524
> >  Read Encryption Key Size (0x05|0x0008) ncmd 1
> >Status: Success (0x00)
> >Handle: 256
> >Key size: 3
> >
> > // WITHOUT PATCH //
> >> ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 5.895023
> >  L2CAP: Connection Request (0x02) ident 3 len 4
> >PSM: 4097 (0x1001)
> >Source CID: 64
> > < ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 5.895213
> >  L2CAP: Connection Response (0x03) ident 3 len 8
> >Destination CID: 64
> >Source CID: 64
> >Result: Connection successful (0x)
> >Status: No further information available (0x)
> >
> > // WITH PATCH //
> >> ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 4.887024
> >  L2CAP: Connection Request (0x02) ident 3 len 4
> >PSM: 4097 (0x1001)
> >Source CID: 64
> > < ACL Data TX: Handle 256 flags 0x00 dlen 16    #43 [hci0] 4.887127
> >  L2CAP: Connection Response (0x03) ident 3 len 8
> >Destination CID: 0
> >Source CID: 64
> >Result: Connection refused - security block (0x0003)
> >Status: No further information available (0x)
> >
> > Signed-off-by: Archie Pusaka 
> >
> > ---
> >
> > Changes in v3:
> > * Move the check to hci_conn_check_link_mode()
> >
> > Changes in v2:
> > * Add btmon trace to the commit message
> >
> > net/bluetooth/hci_conn.c | 4 
> > 1 file changed, 4 insertions(+)
> >
> > diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> > index 9832f8445d43..89085fac797c 100644
> > --- a/net/bluetooth/hci_conn.c
> > +++ b/net/bluetooth/hci_conn.c
> > @@ -1348,6 +1348,10 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
> >   !test_bit(HCI_CONN_ENCRYPT, >flags))
> >   return 0;
> >
> > + if (test_bit(HCI_CONN_ENCRYPT, >flags) &&
> > + conn->enc_key_size < conn->hdev->min_enc_key_size)
> > + return 0;
> > +
> >   return 1;
> > }
>
> I am a bit concerned since we had that check and I on purpose moved it. See 
> commit 693cd8ce3f88 for the change where I removed and commit d5bb334a8e17 
> where I initially added it.
>
> Naively adding the check in that location caused a major regression with 
> Bluetooth 2.0 devices. This makes me a bit reluctant to re-add it here since 
> I restructured the whole change to check the key size a different location.

I have tried this patch (both v2 and v3) to connect with a Bluetooth
2.0 device, it doesn't have any connection problem.
I suppose because in the original patch (d5bb334a8e17), there is no
check for the HCI_CONN_ENCRYPT flag.

>
> Now I have to ask, are you running an upstream kernel with both commits above 
> that address KNOB vulnerability?

Actually no, I haven't heard of KNOB vulnerability before.
This patch is written for qualification purposes, specifically to pass
GAP/SEC/SEM/BI-05-C to BI-08-C.
However, it sounds like it could also prevent some KNOB vulnerability
as a bonus.
>
> Regards
>
> Marcel
>

Thanks,
Archie


[PATCH v2] Bluetooth: send proper config param to unknown config request

2020-09-26 Thread Archie Pusaka
From: Archie Pusaka 

When receiving an L2CAP_CONFIGURATION_REQ with an unknown config
type, currently we will reply with L2CAP_CONFIGURATION_RSP with
a list of unknown types as the config param. However, this is not
a correct format of config param.

As described in the bluetooth spec v5.2, Vol 3, Part A, Sec 5,
the config param should consists of type, length, and optionally
data.

This patch copies the length and data from the received
L2CAP_CONFIGURATION_REQ and also appends them to the config param
of the corresponding L2CAP_CONFIGURATION_RSP to match the format
of the config param according to the spec.

Here's some btmon traces.
//--- Without Patch ---//
> ACL Data RX: Handle 256 flags 0x02 dlen 24   #58 [hci0] 21.570741
  L2CAP: Configure Request (0x04) ident 5 len 16
Destination CID: 64
Flags: 0x
Option: Unknown (0x10) [mandatory]
10 00 11 02 11 00 12 02 12 00..
< ACL Data TX: Handle 256 flags 0x00 dlen 17   #59 [hci0] 21.570892
  L2CAP: Configure Response (0x05) ident 5 len 9
Source CID: 64
Flags: 0x
Result: Failure - unknown options (0x0003)
Option: Unknown (0x10) [mandatory]
12
// Btmon parses it wrong - we sent 10 11 12 instead of just 12.

//--- With Patch ---//
> ACL Data RX: Handle 256 flags 0x02 dlen 24   #58 [hci0] 22.188308
  L2CAP: Configure Request (0x04) ident 9 len 16
Destination CID: 64
Flags: 0x
Option: Unknown (0x10) [mandatory]
10 00 11 02 11 00 12 02 12 00..
< ACL Data TX: Handle 256 flags 0x00 dlen 26   #59 [hci0] 22.188516
  L2CAP: Configure Response (0x05) ident 9 len 18
Source CID: 64
Flags: 0x
Result: Failure - unknown options (0x0003)
Option: Unknown (0x10) [mandatory]
10 00 11 02 11 00 12 02 12 00..

Signed-off-by: Archie Pusaka 
Reviewed-by: Alain Michaud 

---

Changes in v2:
* Add btmon traces in the commit message

 net/bluetooth/l2cap_core.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 1ab27b90ddcb..4e65854b2f1c 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3627,7 +3627,8 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, 
void *data, size_t data
if (hint)
break;
result = L2CAP_CONF_UNKNOWN;
-   *((u8 *) ptr++) = type;
+   l2cap_add_conf_opt(, type, olen, val,
+  endptr - ptr);
break;
}
}
@@ -3658,7 +3659,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, 
void *data, size_t data
}
 
 done:
-   if (chan->mode != rfc.mode) {
+   if (chan->mode != rfc.mode && result != L2CAP_CONF_UNKNOWN) {
result = L2CAP_CONF_UNACCEPT;
rfc.mode = chan->mode;
 
-- 
2.28.0.681.g6f77f65b4e-goog



Re: [PATCH v2] Bluetooth: Check for encryption key size on connect

2020-09-25 Thread Archie Pusaka
Hi Luiz,

On Wed, 23 Sep 2020 at 01:03, Luiz Augusto von Dentz
 wrote:
>
> Hi Archie,
>
> On Tue, Sep 22, 2020 at 12:48 AM Archie Pusaka  wrote:
> >
> > Hi Luiz,
> >
> > On Tue, 22 Sep 2020 at 01:15, Luiz Augusto von Dentz
> >  wrote:
> > >
> > > Hi Archie,
> > >
> > >
> > > On Mon, Sep 21, 2020 at 12:56 AM Archie Pusaka  wrote:
> > > >
> > > > From: Archie Pusaka 
> > > >
> > > > When receiving connection, we only check whether the link has been
> > > > encrypted, but not the encryption key size of the link.
> > > >
> > > > This patch adds check for encryption key size, and reject L2CAP
> > > > connection which size is below the specified threshold (default 7)
> > > > with security block.
> > > >
> > > > Here is some btmon trace.
> > > > @ MGMT Event: New Link Key (0x0009) plen 26{0x0001} [hci0] 5.847722
> > > > Store hint: No (0x00)
> > > > BR/EDR Address: 38:00:25:F7:F1:B0 (OUI 38-00-25)
> > > > Key type: Unauthenticated Combination key from P-192 (0x04)
> > > > Link key: 7bf2f68c81305d63a6b0ee2c5a7a34bc
> > > > PIN length: 0
> > > > > HCI Event: Encryption Change (0x08) plen 4#29 [hci0] 5.871537
> > > > Status: Success (0x00)
> > > > Handle: 256
> > > > Encryption: Enabled with E0 (0x01)
> > > > < HCI Command: Read Encryp... (0x05|0x0008) plen 2  #30 [hci0] 5.871609
> > > > Handle: 256
> > > > > HCI Event: Command Complete (0x0e) plen 7 #31 [hci0] 5.872524
> > > >   Read Encryption Key Size (0x05|0x0008) ncmd 1
> > > > Status: Success (0x00)
> > > > Handle: 256
> > > > Key size: 3
> > > >
> > > > // WITHOUT PATCH //
> > > > > ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 5.895023
> > > >   L2CAP: Connection Request (0x02) ident 3 len 4
> > > > PSM: 4097 (0x1001)
> > > > Source CID: 64
> > > > < ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 5.895213
> > > >   L2CAP: Connection Response (0x03) ident 3 len 8
> > > > Destination CID: 64
> > > > Source CID: 64
> > > > Result: Connection successful (0x)
> > > > Status: No further information available (0x)
> > > >
> > > > // WITH PATCH //
> > > > > ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 4.887024
> > > >   L2CAP: Connection Request (0x02) ident 3 len 4
> > > > PSM: 4097 (0x1001)
> > > > Source CID: 64
> > > > < ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 4.887127
> > > >   L2CAP: Connection Response (0x03) ident 3 len 8
> > > > Destination CID: 0
> > > > Source CID: 64
> > > > Result: Connection refused - security block (0x0003)
> > > > Status: No further information available (0x)
> > > >
> > > > Signed-off-by: Archie Pusaka 
> > > > Reviewed-by: Alain Michaud 
> > > >
> > > > ---
> > > > Btw, it looks like the patch sent by Alex Lu with the title
> > > > [PATCH] Bluetooth: Fix the vulnerable issue on enc key size
> > > > also solves the exact same issue.
> > > >
> > > > Changes in v2:
> > > > * Add btmon trace to the commit message
> > > >
> > > >  net/bluetooth/l2cap_core.c | 3 ++-
> > > >  1 file changed, 2 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> > > > index ade83e224567..b4fc0ad38aaa 100644
> > > > --- a/net/bluetooth/l2cap_core.c
> > > > +++ b/net/bluetooth/l2cap_core.c
> > > > @@ -4101,7 +4101,8 @@ static struct l2cap_chan *l2cap_connect(struct 
> > > > l2cap_conn *conn,
> > > >
> > > > /* Check if the ACL is secure enough (if not SDP) */
> > > > if (psm != cpu_to_le16(L2CAP_PSM_SDP) &&
> > > > -   !hci_conn_check_link_mode(conn->hcon)) {
> > > > +   (!hci_conn_check_link_mode(conn->hcon) ||
> > > > +   !l2cap_check_enc_key_size(conn->hcon))) {
> > >

[PATCH v1] Bluetooth: send proper config param to unknown config request

2020-09-24 Thread Archie Pusaka
From: Archie Pusaka 

When receiving an L2CAP_CONFIGURATION_REQ with an unknown config
type, currently we will reply with L2CAP_CONFIGURATION_RSP with
a list of unknown types as the config param. However, this is not
a correct format of config param.

As described in the bluetooth spec v5.2, Vol 3, Part A, Sec 5,
the config param should consists of type, length, and optionally
data.

This patch copies the length and data from the received
L2CAP_CONFIGURATION_REQ and also appends them to the config param
of the corresponding L2CAP_CONFIGURATION_RSP to match the format
of the config param according to the spec.

Signed-off-by: Archie Pusaka 
Reviewed-by: Alain Michaud 

---

 net/bluetooth/l2cap_core.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ade83e224567..2f3ddd4f0f4c 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3627,7 +3627,8 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, 
void *data, size_t data
if (hint)
break;
result = L2CAP_CONF_UNKNOWN;
-   *((u8 *) ptr++) = type;
+   l2cap_add_conf_opt(, type, olen, val,
+  endptr - ptr);
break;
}
}
@@ -3658,7 +3659,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, 
void *data, size_t data
}
 
 done:
-   if (chan->mode != rfc.mode) {
+   if (chan->mode != rfc.mode && result != L2CAP_CONF_UNKNOWN) {
result = L2CAP_CONF_UNACCEPT;
rfc.mode = chan->mode;
 
-- 
2.28.0.681.g6f77f65b4e-goog



[PATCH v3] Bluetooth: Check for encryption key size on connect

2020-09-22 Thread Archie Pusaka
From: Archie Pusaka 

When receiving connection, we only check whether the link has been
encrypted, but not the encryption key size of the link.

This patch adds check for encryption key size, and reject L2CAP
connection which size is below the specified threshold (default 7)
with security block.

Here is some btmon trace.
@ MGMT Event: New Link Key (0x0009) plen 26{0x0001} [hci0] 5.847722
Store hint: No (0x00)
BR/EDR Address: 38:00:25:F7:F1:B0 (OUI 38-00-25)
Key type: Unauthenticated Combination key from P-192 (0x04)
Link key: 7bf2f68c81305d63a6b0ee2c5a7a34bc
PIN length: 0
> HCI Event: Encryption Change (0x08) plen 4#29 [hci0] 5.871537
Status: Success (0x00)
Handle: 256
Encryption: Enabled with E0 (0x01)
< HCI Command: Read Encryp... (0x05|0x0008) plen 2  #30 [hci0] 5.871609
Handle: 256
> HCI Event: Command Complete (0x0e) plen 7 #31 [hci0] 5.872524
  Read Encryption Key Size (0x05|0x0008) ncmd 1
Status: Success (0x00)
Handle: 256
Key size: 3

// WITHOUT PATCH //
> ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 5.895023
  L2CAP: Connection Request (0x02) ident 3 len 4
PSM: 4097 (0x1001)
Source CID: 64
< ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 5.895213
  L2CAP: Connection Response (0x03) ident 3 len 8
Destination CID: 64
Source CID: 64
Result: Connection successful (0x)
Status: No further information available (0x)

// WITH PATCH //
> ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 4.887024
  L2CAP: Connection Request (0x02) ident 3 len 4
PSM: 4097 (0x1001)
Source CID: 64
< ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 4.887127
  L2CAP: Connection Response (0x03) ident 3 len 8
Destination CID: 0
Source CID: 64
Result: Connection refused - security block (0x0003)
Status: No further information available (0x0000)

Signed-off-by: Archie Pusaka 

---

Changes in v3:
* Move the check to hci_conn_check_link_mode()

Changes in v2:
* Add btmon trace to the commit message

 net/bluetooth/hci_conn.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 9832f8445d43..89085fac797c 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1348,6 +1348,10 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
!test_bit(HCI_CONN_ENCRYPT, >flags))
return 0;
 
+   if (test_bit(HCI_CONN_ENCRYPT, >flags) &&
+   conn->enc_key_size < conn->hdev->min_enc_key_size)
+   return 0;
+
return 1;
 }
 
-- 
2.28.0.681.g6f77f65b4e-goog



Re: [PATCH v2] Bluetooth: Check for encryption key size on connect

2020-09-22 Thread Archie Pusaka
Hi Luiz,

On Tue, 22 Sep 2020 at 01:15, Luiz Augusto von Dentz
 wrote:
>
> Hi Archie,
>
>
> On Mon, Sep 21, 2020 at 12:56 AM Archie Pusaka  wrote:
> >
> > From: Archie Pusaka 
> >
> > When receiving connection, we only check whether the link has been
> > encrypted, but not the encryption key size of the link.
> >
> > This patch adds check for encryption key size, and reject L2CAP
> > connection which size is below the specified threshold (default 7)
> > with security block.
> >
> > Here is some btmon trace.
> > @ MGMT Event: New Link Key (0x0009) plen 26{0x0001} [hci0] 5.847722
> > Store hint: No (0x00)
> > BR/EDR Address: 38:00:25:F7:F1:B0 (OUI 38-00-25)
> > Key type: Unauthenticated Combination key from P-192 (0x04)
> > Link key: 7bf2f68c81305d63a6b0ee2c5a7a34bc
> > PIN length: 0
> > > HCI Event: Encryption Change (0x08) plen 4#29 [hci0] 5.871537
> > Status: Success (0x00)
> > Handle: 256
> > Encryption: Enabled with E0 (0x01)
> > < HCI Command: Read Encryp... (0x05|0x0008) plen 2  #30 [hci0] 5.871609
> > Handle: 256
> > > HCI Event: Command Complete (0x0e) plen 7 #31 [hci0] 5.872524
> >   Read Encryption Key Size (0x05|0x0008) ncmd 1
> > Status: Success (0x00)
> > Handle: 256
> > Key size: 3
> >
> > // WITHOUT PATCH //
> > > ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 5.895023
> >   L2CAP: Connection Request (0x02) ident 3 len 4
> > PSM: 4097 (0x1001)
> > Source CID: 64
> > < ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 5.895213
> >   L2CAP: Connection Response (0x03) ident 3 len 8
> > Destination CID: 64
> > Source CID: 64
> > Result: Connection successful (0x)
> > Status: No further information available (0x)
> >
> > // WITH PATCH //
> > > ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 4.887024
> >   L2CAP: Connection Request (0x02) ident 3 len 4
> > PSM: 4097 (0x1001)
> > Source CID: 64
> > < ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 4.887127
> >   L2CAP: Connection Response (0x03) ident 3 len 8
> > Destination CID: 0
> > Source CID: 64
> > Result: Connection refused - security block (0x0003)
> > Status: No further information available (0x)
> >
> > Signed-off-by: Archie Pusaka 
> > Reviewed-by: Alain Michaud 
> >
> > ---
> > Btw, it looks like the patch sent by Alex Lu with the title
> > [PATCH] Bluetooth: Fix the vulnerable issue on enc key size
> > also solves the exact same issue.
> >
> > Changes in v2:
> > * Add btmon trace to the commit message
> >
> >  net/bluetooth/l2cap_core.c | 3 ++-
> >  1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> > index ade83e224567..b4fc0ad38aaa 100644
> > --- a/net/bluetooth/l2cap_core.c
> > +++ b/net/bluetooth/l2cap_core.c
> > @@ -4101,7 +4101,8 @@ static struct l2cap_chan *l2cap_connect(struct 
> > l2cap_conn *conn,
> >
> > /* Check if the ACL is secure enough (if not SDP) */
> > if (psm != cpu_to_le16(L2CAP_PSM_SDP) &&
> > -   !hci_conn_check_link_mode(conn->hcon)) {
> > +   (!hci_conn_check_link_mode(conn->hcon) ||
> > +   !l2cap_check_enc_key_size(conn->hcon))) {
>
> I wonder if we couldn't incorporate the check of key size into
> hci_conn_check_link_mode, like I said in the first patch checking the
> enc key size should not be specific to L2CAP.

Yes, I could move the check into hci_conn_check_link_mode.
At first look, this function is also called by AMP which I am not
familiar with. In addition, I found this patch which moves this check
outside hci_conn, so I have my doubts there.
https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git/commit/?id=693cd8ce3f882524a5d06f7800dd8492411877b3

>
> > conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
> > result = L2CAP_CR_SEC_BLOCK;
> > goto response;
> > --
> > 2.28.0.681.g6f77f65b4e-goog
> >
>
>
> --
> Luiz Augusto von Dentz

Thanks,
Archie


Re: [PATCH v1] Bluetooth: Enforce key size of 16 bytes on FIPS level

2020-09-22 Thread Archie Pusaka
Hi Luiz,

On Tue, 22 Sep 2020 at 01:13, Luiz Augusto von Dentz
 wrote:
>
> Hi Archie,
>
> On Mon, Sep 21, 2020 at 1:31 AM Archie Pusaka  wrote:
> >
> > From: Archie Pusaka 
> >
> > According to the spec Ver 5.2, Vol 3, Part C, Sec 5.2.2.8:
> > Device in security mode 4 level 4 shall enforce:
> > 128-bit equivalent strength for link and encryption keys required
> > using FIPS approved algorithms (E0 not allowed, SAFER+ not allowed,
> > and P-192 not allowed; encryption key not shortened)
> >
> > This patch rejects connection with key size below 16 for FIPS level
> > services.
> >
> > Signed-off-by: Archie Pusaka 
> > Reviewed-by: Alain Michaud 
> >
> > ---
> >
> >  net/bluetooth/l2cap_core.c | 7 ++-
> >  1 file changed, 6 insertions(+), 1 deletion(-)
> >
> > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> > index ade83e224567..306616ec26e6 100644
> > --- a/net/bluetooth/l2cap_core.c
> > +++ b/net/bluetooth/l2cap_core.c
> > @@ -1515,8 +1515,13 @@ static bool l2cap_check_enc_key_size(struct hci_conn 
> > *hcon)
> >  * that have no key size requirements. Ensure that the link is
> >  * actually encrypted before enforcing a key size.
> >  */
> > +   int min_key_size = hcon->hdev->min_enc_key_size;
> > +
> > +   if (hcon->sec_level == BT_SECURITY_FIPS)
> > +   min_key_size = 16;
> > +
> > return (!test_bit(HCI_CONN_ENCRYPT, >flags) ||
> > -   hcon->enc_key_size >= hcon->hdev->min_enc_key_size);
> > +   hcon->enc_key_size >= min_key_size);
>
> While this looks fine to me, it looks like this should be placed
> elsewhere since it takes an hci_conn and it is not L2CAP specific.

>From what I understood, it is permissible to use AES-CCM P-256
encryption with key length < 16 when encrypting the link, but such a
connection does not satisfy security level 4, and therefore must not
be given access to level 4 services. However, I think it is
permissible to give them access to level 3 services or below.

Should I use l2cap chan->sec_level for this purpose? I'm kind of lost
on the difference between hcon->sec_level and chan->sec_level.

>
> >  }
> >
> >  static void l2cap_do_start(struct l2cap_chan *chan)
> > --
> > 2.28.0.681.g6f77f65b4e-goog
> >
>
>
> --
> Luiz Augusto von Dentz


[PATCH v1] Bluetooth: Enforce key size of 16 bytes on FIPS level

2020-09-21 Thread Archie Pusaka
From: Archie Pusaka 

According to the spec Ver 5.2, Vol 3, Part C, Sec 5.2.2.8:
Device in security mode 4 level 4 shall enforce:
128-bit equivalent strength for link and encryption keys required
using FIPS approved algorithms (E0 not allowed, SAFER+ not allowed,
and P-192 not allowed; encryption key not shortened)

This patch rejects connection with key size below 16 for FIPS level
services.

Signed-off-by: Archie Pusaka 
Reviewed-by: Alain Michaud 

---

 net/bluetooth/l2cap_core.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ade83e224567..306616ec26e6 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1515,8 +1515,13 @@ static bool l2cap_check_enc_key_size(struct hci_conn 
*hcon)
 * that have no key size requirements. Ensure that the link is
 * actually encrypted before enforcing a key size.
 */
+   int min_key_size = hcon->hdev->min_enc_key_size;
+
+   if (hcon->sec_level == BT_SECURITY_FIPS)
+   min_key_size = 16;
+
return (!test_bit(HCI_CONN_ENCRYPT, >flags) ||
-   hcon->enc_key_size >= hcon->hdev->min_enc_key_size);
+   hcon->enc_key_size >= min_key_size);
 }
 
 static void l2cap_do_start(struct l2cap_chan *chan)
-- 
2.28.0.681.g6f77f65b4e-goog



[PATCH v2] Bluetooth: Check for encryption key size on connect

2020-09-21 Thread Archie Pusaka
From: Archie Pusaka 

When receiving connection, we only check whether the link has been
encrypted, but not the encryption key size of the link.

This patch adds check for encryption key size, and reject L2CAP
connection which size is below the specified threshold (default 7)
with security block.

Here is some btmon trace.
@ MGMT Event: New Link Key (0x0009) plen 26{0x0001} [hci0] 5.847722
Store hint: No (0x00)
BR/EDR Address: 38:00:25:F7:F1:B0 (OUI 38-00-25)
Key type: Unauthenticated Combination key from P-192 (0x04)
Link key: 7bf2f68c81305d63a6b0ee2c5a7a34bc
PIN length: 0
> HCI Event: Encryption Change (0x08) plen 4#29 [hci0] 5.871537
Status: Success (0x00)
Handle: 256
Encryption: Enabled with E0 (0x01)
< HCI Command: Read Encryp... (0x05|0x0008) plen 2  #30 [hci0] 5.871609
Handle: 256
> HCI Event: Command Complete (0x0e) plen 7 #31 [hci0] 5.872524
  Read Encryption Key Size (0x05|0x0008) ncmd 1
Status: Success (0x00)
Handle: 256
Key size: 3

// WITHOUT PATCH //
> ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 5.895023
  L2CAP: Connection Request (0x02) ident 3 len 4
PSM: 4097 (0x1001)
Source CID: 64
< ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 5.895213
  L2CAP: Connection Response (0x03) ident 3 len 8
Destination CID: 64
Source CID: 64
Result: Connection successful (0x)
Status: No further information available (0x)

// WITH PATCH //
> ACL Data RX: Handle 256 flags 0x02 dlen 12#42 [hci0] 4.887024
  L2CAP: Connection Request (0x02) ident 3 len 4
PSM: 4097 (0x1001)
Source CID: 64
< ACL Data TX: Handle 256 flags 0x00 dlen 16#43 [hci0] 4.887127
  L2CAP: Connection Response (0x03) ident 3 len 8
Destination CID: 0
Source CID: 64
Result: Connection refused - security block (0x0003)
Status: No further information available (0x0000)

Signed-off-by: Archie Pusaka 
Reviewed-by: Alain Michaud 

---
Btw, it looks like the patch sent by Alex Lu with the title
[PATCH] Bluetooth: Fix the vulnerable issue on enc key size
also solves the exact same issue.

Changes in v2:
* Add btmon trace to the commit message

 net/bluetooth/l2cap_core.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ade83e224567..b4fc0ad38aaa 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4101,7 +4101,8 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn 
*conn,
 
/* Check if the ACL is secure enough (if not SDP) */
if (psm != cpu_to_le16(L2CAP_PSM_SDP) &&
-   !hci_conn_check_link_mode(conn->hcon)) {
+   (!hci_conn_check_link_mode(conn->hcon) ||
+   !l2cap_check_enc_key_size(conn->hcon))) {
conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
result = L2CAP_CR_SEC_BLOCK;
goto response;
-- 
2.28.0.681.g6f77f65b4e-goog



[PATCH v1] Bluetooth: Check for encryption key size on connect

2020-09-17 Thread Archie Pusaka
From: Archie Pusaka 

When receiving connection, we only check whether the link has been
encrypted, but not the encryption key size of the link.

This patch adds check for encryption key size, and reject L2CAP
connection which size is below the specified threshold (default 7)
with security block.

Signed-off-by: Archie Pusaka 
Reviewed-by: Alain Michaud 

---

 net/bluetooth/l2cap_core.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ade83e224567..b4fc0ad38aaa 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4101,7 +4101,8 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn 
*conn,
 
/* Check if the ACL is secure enough (if not SDP) */
if (psm != cpu_to_le16(L2CAP_PSM_SDP) &&
-   !hci_conn_check_link_mode(conn->hcon)) {
+   (!hci_conn_check_link_mode(conn->hcon) ||
+   !l2cap_check_enc_key_size(conn->hcon))) {
conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
result = L2CAP_CR_SEC_BLOCK;
goto response;
-- 
2.28.0.681.g6f77f65b4e-goog



Re: [RFC PATCH v1 1/2] Bluetooth: queue ACL packets if no handle is found

2020-06-30 Thread Archie Pusaka
Hi Marcel,

On Mon, 29 Jun 2020 at 14:40, Marcel Holtmann  wrote:
>
> Hi Archie,
>
> > There is a possibility that an ACL packet is received before we
> > receive the HCI connect event for the corresponding handle. If this
> > happens, we discard the ACL packet.
> >
> > Rather than just ignoring them, this patch provides a queue for
> > incoming ACL packet without a handle. The queue is processed when
> > receiving a HCI connection event. If 2 seconds elapsed without
> > receiving the HCI connection event, assume something bad happened
> > and discard the queued packet.
> >
> > Signed-off-by: Archie Pusaka 
> > Reviewed-by: Abhishek Pandit-Subedi 
>
> so two things up front. I want to hide this behind a 
> HCI_QUIRK_OUT_OF_ORDER_ACL that a transport driver has to set first. Frankly 
> if this kind of out-of-order happens on UART or SDIO transports, then 
> something is obviously going wrong. I have no plan to fix up after a fully 
> serialized transport.
>
> Secondly, if a transport sets HCI_QUIRK_OUT_OF_ORDER_ACL, then I want this 
> off by default. You can enable it via an experimental setting. The reason 
> here is that we have to make it really hard and fail as often as possible so 
> that hardware manufactures and spec writers realize that something is 
> fundamentally broken here.
>
> I have no problem in running the code and complaining loudly in case the 
> quirk has been set. Just injecting the packets can only happen if bluetoothd 
> explicitly enabled it.

Got it.

>
>
> >
> > ---
> >
> > include/net/bluetooth/hci_core.h |  8 +++
> > net/bluetooth/hci_core.c | 84 +---
> > net/bluetooth/hci_event.c|  2 +
> > 3 files changed, 88 insertions(+), 6 deletions(-)
> >
> > diff --git a/include/net/bluetooth/hci_core.h 
> > b/include/net/bluetooth/hci_core.h
> > index 836dc997ff94..b69ecdd0d15a 100644
> > --- a/include/net/bluetooth/hci_core.h
> > +++ b/include/net/bluetooth/hci_core.h
> > @@ -270,6 +270,9 @@ struct adv_monitor {
> > /* Default authenticated payload timeout 30s */
> > #define DEFAULT_AUTH_PAYLOAD_TIMEOUT   0x0bb8
> >
> > +/* Time to keep ACL packets without a corresponding handle queued (2s) */
> > +#define PENDING_ACL_TIMEOUT  msecs_to_jiffies(2000)
> > +
>
> Do we have some btmon traces with timestamps. Isn’t a second enough? Actually 
> 2 seconds is an awful long time.

When this happens in the test lab, the HCI connect event is about
0.002 second behind the first ACL packet. We can change this if
required.

>
> > struct amp_assoc {
> >   __u16   len;
> >   __u16   offset;
> > @@ -538,6 +541,9 @@ struct hci_dev {
> >   struct delayed_work rpa_expired;
> >   bdaddr_trpa;
> >
> > + struct delayed_work remove_pending_acl;
> > + struct sk_buff_head pending_acl_q;
> > +
>
> can we name this ooo_q and move it to the other queues in this struct. Unless 
> we want to add a Kconfig option around it, we don’t need to keep it here.

Ack.

>
> > #if IS_ENABLED(CONFIG_BT_LEDS)
> >   struct led_trigger  *power_led;
> > #endif
> > @@ -1773,6 +1779,8 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 
> > ediv, __le64 rand,
> > void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
> >  u8 *bdaddr_type);
> >
> > +void hci_process_pending_acl(struct hci_dev *hdev, struct hci_conn *conn);
> > +
> > #define SCO_AIRMODE_MASK   0x0003
> > #define SCO_AIRMODE_CVSD   0x
> > #define SCO_AIRMODE_TRANSP 0x0003
> > diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> > index 7959b851cc63..30780242c267 100644
> > --- a/net/bluetooth/hci_core.c
> > +++ b/net/bluetooth/hci_core.c
> > @@ -1786,6 +1786,7 @@ int hci_dev_do_close(struct hci_dev *hdev)
> >   skb_queue_purge(>rx_q);
> >   skb_queue_purge(>cmd_q);
> >   skb_queue_purge(>raw_q);
> > + skb_queue_purge(>pending_acl_q);
> >
> >   /* Drop last sent command */
> >   if (hdev->sent_cmd) {
> > @@ -3518,6 +3519,78 @@ static int hci_suspend_notifier(struct 
> > notifier_block *nb, unsigned long action,
> >   return NOTIFY_STOP;
> > }
> >
> > +static void hci_add_pending_acl(struct hci_dev *hdev, struct sk_buff *skb)
> > +{
> > + skb_queue_tail(>pending_acl_q, skb);
> > +
> > + queue_delayed_work(hdev->workqueue, >remove_pending_acl,
> > +  

[RFC PATCH v1 2/2] Bluetooth: queue L2CAP conn req if encryption is needed

2020-06-27 Thread Archie Pusaka
From: Archie Pusaka 

It is possible to receive an L2CAP conn req for an encrypted
connection, before actually receiving the HCI change encryption
event. If this happened, the received L2CAP packet will be ignored.

This patch queues the L2CAP packet and process them after the
expected HCI event is received. If after 2 seconds we still don't
receive it, then we assume something bad happened and discard the
queued packets.

Signed-off-by: Archie Pusaka 
Reviewed-by: Abhishek Pandit-Subedi 

---

 include/net/bluetooth/bluetooth.h |  6 +++
 include/net/bluetooth/l2cap.h |  6 +++
 net/bluetooth/hci_event.c |  3 ++
 net/bluetooth/l2cap_core.c| 87 +++
 4 files changed, 91 insertions(+), 11 deletions(-)

diff --git a/include/net/bluetooth/bluetooth.h 
b/include/net/bluetooth/bluetooth.h
index 7ee8041af803..e64278401084 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -335,7 +335,11 @@ struct l2cap_ctrl {
u16 reqseq;
u16 txseq;
u8  retries;
+   u8  rsp_code;
+   u8  amp_id;
+   __u8ident;
__le16  psm;
+   __le16  scid;
bdaddr_t bdaddr;
struct l2cap_chan *chan;
 };
@@ -374,6 +378,8 @@ struct bt_skb_cb {
struct hci_ctrl hci;
};
 };
+static_assert(sizeof(struct bt_skb_cb) <= sizeof(((struct sk_buff *)0)->cb));
+
 #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
 
 #define hci_skb_pkt_type(skb) bt_cb((skb))->pkt_type
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 8f1e6a7a2df8..f8f6dec96f12 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -58,6 +58,7 @@
 #define L2CAP_MOVE_ERTX_TIMEOUTmsecs_to_jiffies(6)
 #define L2CAP_WAIT_ACK_POLL_PERIOD msecs_to_jiffies(200)
 #define L2CAP_WAIT_ACK_TIMEOUT msecs_to_jiffies(1)
+#define L2CAP_PEND_ENC_CONN_TIMEOUTmsecs_to_jiffies(2000)
 
 #define L2CAP_A2MP_DEFAULT_MTU 670
 
@@ -700,6 +701,9 @@ struct l2cap_conn {
struct mutexchan_lock;
struct kref ref;
struct list_headusers;
+
+   struct delayed_work remove_pending_encrypt_conn;
+   struct sk_buff_head pending_conn_q;
 };
 
 struct l2cap_user {
@@ -1001,4 +1005,6 @@ void l2cap_conn_put(struct l2cap_conn *conn);
 int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user);
 void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user);
 
+void l2cap_process_pending_encrypt_conn(struct hci_conn *hcon);
+
 #endif /* __L2CAP_H */
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 108c6c102a6a..8cefc51a5ca4 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3136,6 +3136,9 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, 
struct sk_buff *skb)
 
 unlock:
hci_dev_unlock(hdev);
+
+   if (conn && !ev->status && ev->encrypt)
+   l2cap_process_pending_encrypt_conn(conn);
 }
 
 static void hci_change_link_key_complete_evt(struct hci_dev *hdev,
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 35d2bc569a2d..fc6fe2c80c46 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -62,6 +62,10 @@ static void l2cap_send_disconn_req(struct l2cap_chan *chan, 
int err);
 static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
 struct sk_buff_head *skbs, u8 event);
 
+static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
+   u8 ident, u8 *data, u8 rsp_code,
+   u8 amp_id, bool queue_if_fail);
+
 static inline u8 bdaddr_type(u8 link_type, u8 bdaddr_type)
 {
if (link_type == LE_LINK) {
@@ -1902,6 +1906,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
cancel_delayed_work_sync(>info_timer);
 
+   cancel_delayed_work_sync(>remove_pending_encrypt_conn);
+
hcon->l2cap_data = NULL;
conn->hchan = NULL;
l2cap_conn_put(conn);
@@ -2023,6 +2029,55 @@ static void l2cap_retrans_timeout(struct work_struct 
*work)
l2cap_chan_put(chan);
 }
 
+static void l2cap_add_pending_encrypt_conn(struct l2cap_conn *conn,
+  struct l2cap_conn_req *req,
+  u8 ident, u8 rsp_code, u8 amp_id)
+{
+   struct sk_buff *skb = bt_skb_alloc(0, GFP_KERNEL);
+
+   bt_cb(skb)->l2cap.psm = req->psm;
+   bt_cb(skb)->l2cap.scid = req->scid;
+   bt_cb(skb)->l2cap.ident = ident;
+   bt_cb(skb)->l2cap.rsp_code = rsp_code;
+   bt_cb(skb)->l2cap.amp_id = amp_id;
+
+   skb_queue_tail(>

[RFC PATCH v1 0/2] handle USB endpoint race condition

2020-06-27 Thread Archie Pusaka
From: Archie Pusaka 

On platforms with USB transport, events and data are transferred via
different endpoints. This could potentially cause ordering problems,
where the order of processed information is different than the actual
order.

One such a case is we receive a ACL packet before receiving the
connect complete event. This could be frequently observed on ChromeOS
auto test setup.

> ACL Data RX: Handle 256 flags 0x02 dlen 12   #6 [hci0] 9.314240
  L2CAP: Connection Request (0x02) ident 1 len 4
PSM: 1 (0x0001)
Source CID: 1536
> HCI Event: Connect Complete (0x03) plen 11   #7 [hci0] 9.333236
Status: Success (0x00)
Handle: 256
Address: 70:BF:92:CF:95:B7 (OUI 70-BF-92)
Link type: ACL (0x01)
Encryption: Disabled (0x00)

If this happens, we will simply discard the ACL packet, since no
corresponding handle is registered yet. The situation where the ACL
packet is not replied by us is handled differently by each peripheral:
some will resend the ACL packet (which will be successful, since the
handle can be found now), but some will get upset and disconnect.

To prevent this from happening, we propose to introduce a queue. So,
instead of discarding those packets without handle, we put them in a
queue. Then, we will process this queue when we receive a connect
completion event for the matching handle. The queued packets will be
cleared if after 2 seconds we still don't receive the corresponding
connect complete event.

Similarly, there is a chance that the incoming L2CAP connection
request comes before HCI encryption change event. When this happens,
the incoming connection will be refused.
> ACL Data RX: Handle 256 flags 0x02 dlen 12  #46 [hci0] 9.275297
  L2CAP: Connection Request (0x02) ident 4 len 4
PSM: 3 (0x0003)
Source CID: 256
< ACL Data TX: Handle 256 flags 0x00 dlen 16  #47 [hci0] 9.275393
  L2CAP: Connection Response (0x03) ident 4 len 8
Destination CID: 0
Source CID: 256
Result: Connection refused - security block (0x0003)
Status: No further information available (0x)
> HCI Event: Encryption Change (0x08) plen 4  #51 [hci0] 9.314109
Status: Success (0x00)
Handle: 256
Encryption: Enabled with E0 (0x01)

We propose to handle this case with a similar solution: queuing the
L2CAP connection request until we receive HCI encryption change.

The proposed patch is tested with a special Intel firmware which
allows us to purposely delay the "connect complete" event.

We plan to merge this change to ChromeOS auto test setup to see
whether this could fix the problem there, but we also would like
to have your input on this in the meantime.

Thanks,
Archie


Archie Pusaka (2):
  Bluetooth: queue ACL packets if no handle is found
  Bluetooth: queue L2CAP conn req if encryption is needed

 include/net/bluetooth/bluetooth.h |  6 +++
 include/net/bluetooth/hci_core.h  |  8 +++
 include/net/bluetooth/l2cap.h |  6 +++
 net/bluetooth/hci_core.c  | 84 ++---
 net/bluetooth/hci_event.c |  5 ++
 net/bluetooth/l2cap_core.c| 87 +++
 6 files changed, 179 insertions(+), 17 deletions(-)

-- 
2.27.0.212.ge8ba1cc988-goog



[RFC PATCH v1 1/2] Bluetooth: queue ACL packets if no handle is found

2020-06-27 Thread Archie Pusaka
From: Archie Pusaka 

There is a possibility that an ACL packet is received before we
receive the HCI connect event for the corresponding handle. If this
happens, we discard the ACL packet.

Rather than just ignoring them, this patch provides a queue for
incoming ACL packet without a handle. The queue is processed when
receiving a HCI connection event. If 2 seconds elapsed without
receiving the HCI connection event, assume something bad happened
and discard the queued packet.

Signed-off-by: Archie Pusaka 
Reviewed-by: Abhishek Pandit-Subedi 

---

 include/net/bluetooth/hci_core.h |  8 +++
 net/bluetooth/hci_core.c | 84 +---
 net/bluetooth/hci_event.c|  2 +
 3 files changed, 88 insertions(+), 6 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 836dc997ff94..b69ecdd0d15a 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -270,6 +270,9 @@ struct adv_monitor {
 /* Default authenticated payload timeout 30s */
 #define DEFAULT_AUTH_PAYLOAD_TIMEOUT   0x0bb8
 
+/* Time to keep ACL packets without a corresponding handle queued (2s) */
+#define PENDING_ACL_TIMEOUTmsecs_to_jiffies(2000)
+
 struct amp_assoc {
__u16   len;
__u16   offset;
@@ -538,6 +541,9 @@ struct hci_dev {
struct delayed_work rpa_expired;
bdaddr_trpa;
 
+   struct delayed_work remove_pending_acl;
+   struct sk_buff_head pending_acl_q;
+
 #if IS_ENABLED(CONFIG_BT_LEDS)
struct led_trigger  *power_led;
 #endif
@@ -1773,6 +1779,8 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, 
__le64 rand,
 void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
   u8 *bdaddr_type);
 
+void hci_process_pending_acl(struct hci_dev *hdev, struct hci_conn *conn);
+
 #define SCO_AIRMODE_MASK   0x0003
 #define SCO_AIRMODE_CVSD   0x
 #define SCO_AIRMODE_TRANSP 0x0003
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 7959b851cc63..30780242c267 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1786,6 +1786,7 @@ int hci_dev_do_close(struct hci_dev *hdev)
skb_queue_purge(>rx_q);
skb_queue_purge(>cmd_q);
skb_queue_purge(>raw_q);
+   skb_queue_purge(>pending_acl_q);
 
/* Drop last sent command */
if (hdev->sent_cmd) {
@@ -3518,6 +3519,78 @@ static int hci_suspend_notifier(struct notifier_block 
*nb, unsigned long action,
return NOTIFY_STOP;
 }
 
+static void hci_add_pending_acl(struct hci_dev *hdev, struct sk_buff *skb)
+{
+   skb_queue_tail(>pending_acl_q, skb);
+
+   queue_delayed_work(hdev->workqueue, >remove_pending_acl,
+  PENDING_ACL_TIMEOUT);
+}
+
+void hci_process_pending_acl(struct hci_dev *hdev, struct hci_conn *conn)
+{
+   struct sk_buff *skb, *tmp;
+   struct hci_acl_hdr *hdr;
+   u16 handle, flags;
+   bool reset_timer = false;
+
+   skb_queue_walk_safe(>pending_acl_q, skb, tmp) {
+   hdr = (struct hci_acl_hdr *)skb->data;
+   handle = __le16_to_cpu(hdr->handle);
+   flags  = hci_flags(handle);
+   handle = hci_handle(handle);
+
+   if (handle != conn->handle)
+   continue;
+
+   __skb_unlink(skb, >pending_acl_q);
+   skb_pull(skb, HCI_ACL_HDR_SIZE);
+
+   l2cap_recv_acldata(conn, skb, flags);
+   reset_timer = true;
+   }
+
+   if (reset_timer)
+   mod_delayed_work(hdev->workqueue, >remove_pending_acl,
+PENDING_ACL_TIMEOUT);
+}
+
+/* Remove the oldest pending ACL, and all pending ACLs with the same handle */
+static void hci_remove_pending_acl(struct work_struct *work)
+{
+   struct hci_dev *hdev;
+   struct sk_buff *skb, *tmp;
+   struct hci_acl_hdr *hdr;
+   u16 handle, oldest_handle;
+
+   hdev = container_of(work, struct hci_dev, remove_pending_acl.work);
+   skb = skb_dequeue(>pending_acl_q);
+
+   if (!skb)
+   return;
+
+   hdr = (struct hci_acl_hdr *)skb->data;
+   oldest_handle = hci_handle(__le16_to_cpu(hdr->handle));
+   kfree_skb(skb);
+
+   bt_dev_err(hdev, "ACL packet for unknown connection handle %d",
+  oldest_handle);
+
+   skb_queue_walk_safe(>pending_acl_q, skb, tmp) {
+   hdr = (struct hci_acl_hdr *)skb->data;
+   handle = hci_handle(__le16_to_cpu(hdr->handle));
+
+   if (handle == oldest_handle) {
+   __skb_unlink(skb, >pending_acl_q);
+   kfree_skb(skb);
+   }
+   }
+
+   if (!skb_queue_empty(>pending_acl_q))
+   queue_delayed_work(hdev->workqueue, >remove_pending_ac