2015-03-17 14:48:48 +03:00
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright ( C ) 2015 Intel Corporation
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation ;
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS
OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS .
IN NO EVENT SHALL THE COPYRIGHT HOLDER ( S ) AND AUTHOR ( S ) BE LIABLE FOR ANY
CLAIM , OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES , OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
ALL LIABILITY , INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS ,
COPYRIGHTS , TRADEMARKS OR OTHER RIGHTS , RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED .
*/
2016-08-27 21:23:41 +03:00
# include <asm/unaligned.h>
2015-03-17 14:48:48 +03:00
# include <net/bluetooth/bluetooth.h>
# include <net/bluetooth/hci_core.h>
2016-08-27 21:23:41 +03:00
# include <net/bluetooth/hci_mon.h>
2015-03-17 14:48:48 +03:00
# include <net/bluetooth/mgmt.h>
# include "mgmt_util.h"
2016-08-27 21:23:41 +03:00
static struct sk_buff * create_monitor_ctrl_event ( __le16 index , u32 cookie ,
u16 opcode , u16 len , void * buf )
{
struct hci_mon_hdr * hdr ;
struct sk_buff * skb ;
skb = bt_skb_alloc ( 6 + len , GFP_ATOMIC ) ;
if ( ! skb )
return NULL ;
put_unaligned_le32 ( cookie , skb_put ( skb , 4 ) ) ;
put_unaligned_le16 ( opcode , skb_put ( skb , 2 ) ) ;
if ( buf )
networking: introduce and use skb_put_data()
A common pattern with skb_put() is to just want to memcpy()
some data into the new space, introduce skb_put_data() for
this.
An spatch similar to the one for skb_put_zero() converts many
of the places using it:
@@
identifier p, p2;
expression len, skb, data;
type t, t2;
@@
(
-p = skb_put(skb, len);
+p = skb_put_data(skb, data, len);
|
-p = (t)skb_put(skb, len);
+p = skb_put_data(skb, data, len);
)
(
p2 = (t2)p;
-memcpy(p2, data, len);
|
-memcpy(p, data, len);
)
@@
type t, t2;
identifier p, p2;
expression skb, data;
@@
t *p;
...
(
-p = skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
|
-p = (t *)skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
)
(
p2 = (t2)p;
-memcpy(p2, data, sizeof(*p));
|
-memcpy(p, data, sizeof(*p));
)
@@
expression skb, len, data;
@@
-memcpy(skb_put(skb, len), data, len);
+skb_put_data(skb, data, len);
(again, manually post-processed to retain some comments)
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:20 +03:00
skb_put_data ( skb , buf , len ) ;
2016-08-27 21:23:41 +03:00
__net_timestamp ( skb ) ;
networking: make skb_push & __skb_push return void pointers
It seems like a historic accident that these return unsigned char *,
and in many places that means casts are required, more often than not.
Make these functions return void * and remove all the casts across
the tree, adding a (u8 *) cast only where the unsigned char pointer
was used directly, all done with the following spatch:
@@
expression SKB, LEN;
typedef u8;
identifier fn = { skb_push, __skb_push, skb_push_rcsum };
@@
- *(fn(SKB, LEN))
+ *(u8 *)fn(SKB, LEN)
@@
expression E, SKB, LEN;
identifier fn = { skb_push, __skb_push, skb_push_rcsum };
type T;
@@
- E = ((T *)(fn(SKB, LEN)))
+ E = fn(SKB, LEN)
@@
expression SKB, LEN;
identifier fn = { skb_push, __skb_push, skb_push_rcsum };
@@
- fn(SKB, LEN)[0]
+ *(u8 *)fn(SKB, LEN)
Note that the last part there converts from push(...)[0] to the
more idiomatic *(u8 *)push(...).
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:23 +03:00
hdr = skb_push ( skb , HCI_MON_HDR_SIZE ) ;
2016-08-27 21:23:41 +03:00
hdr - > opcode = cpu_to_le16 ( HCI_MON_CTRL_EVENT ) ;
hdr - > index = index ;
hdr - > len = cpu_to_le16 ( skb - > len - HCI_MON_HDR_SIZE ) ;
return skb ;
}
2021-12-04 03:15:40 +03:00
struct sk_buff * mgmt_alloc_skb ( struct hci_dev * hdev , u16 opcode ,
unsigned int size )
2015-03-17 14:48:48 +03:00
{
struct sk_buff * skb ;
2021-12-04 03:15:40 +03:00
skb = alloc_skb ( sizeof ( struct mgmt_hdr ) + size , GFP_KERNEL ) ;
2015-03-17 14:48:48 +03:00
if ( ! skb )
2021-12-04 03:15:40 +03:00
return skb ;
2015-03-17 14:48:48 +03:00
2021-12-04 03:15:40 +03:00
skb_reserve ( skb , sizeof ( struct mgmt_hdr ) ) ;
bt_cb ( skb ) - > mgmt . hdev = hdev ;
bt_cb ( skb ) - > mgmt . opcode = opcode ;
2015-03-17 14:48:48 +03:00
2021-12-04 03:15:40 +03:00
return skb ;
}
int mgmt_send_event_skb ( unsigned short channel , struct sk_buff * skb , int flag ,
struct sock * skip_sk )
{
struct hci_dev * hdev ;
struct mgmt_hdr * hdr ;
2022-02-15 05:01:56 +03:00
int len ;
2021-12-04 03:15:40 +03:00
if ( ! skb )
return - EINVAL ;
2022-02-15 05:01:56 +03:00
len = skb - > len ;
2021-12-04 03:15:40 +03:00
hdev = bt_cb ( skb ) - > mgmt . hdev ;
2015-03-17 14:48:48 +03:00
/* Time stamp */
__net_timestamp ( skb ) ;
2021-12-04 03:15:40 +03:00
/* Send just the data, without headers, to the monitor */
2016-08-27 21:23:41 +03:00
if ( channel = = HCI_CHANNEL_CONTROL )
2021-12-04 03:15:40 +03:00
hci_send_monitor_ctrl_event ( hdev , bt_cb ( skb ) - > mgmt . opcode ,
skb - > data , skb - > len ,
2016-08-27 21:23:41 +03:00
skb_get_ktime ( skb ) , flag , skip_sk ) ;
2021-12-04 03:15:40 +03:00
hdr = skb_push ( skb , sizeof ( * hdr ) ) ;
hdr - > opcode = cpu_to_le16 ( bt_cb ( skb ) - > mgmt . opcode ) ;
if ( hdev )
hdr - > index = cpu_to_le16 ( hdev - > id ) ;
else
hdr - > index = cpu_to_le16 ( MGMT_INDEX_NONE ) ;
hdr - > len = cpu_to_le16 ( len ) ;
hci_send_to_channel ( channel , skb , flag , skip_sk ) ;
2016-08-27 21:23:41 +03:00
kfree_skb ( skb ) ;
2015-03-17 14:48:48 +03:00
return 0 ;
}
2021-12-04 03:15:40 +03:00
int mgmt_send_event ( u16 event , struct hci_dev * hdev , unsigned short channel ,
void * data , u16 data_len , int flag , struct sock * skip_sk )
{
struct sk_buff * skb ;
skb = mgmt_alloc_skb ( hdev , event , data_len ) ;
if ( ! skb )
return - ENOMEM ;
if ( data )
skb_put_data ( skb , data , data_len ) ;
return mgmt_send_event_skb ( channel , skb , flag , skip_sk ) ;
}
2015-03-17 14:48:48 +03:00
int mgmt_cmd_status ( struct sock * sk , u16 index , u16 cmd , u8 status )
{
2016-08-27 21:23:41 +03:00
struct sk_buff * skb , * mskb ;
2015-03-17 14:48:48 +03:00
struct mgmt_hdr * hdr ;
struct mgmt_ev_cmd_status * ev ;
int err ;
BT_DBG ( " sock %p, index %u, cmd %u, status %u " , sk , index , cmd , status ) ;
skb = alloc_skb ( sizeof ( * hdr ) + sizeof ( * ev ) , GFP_KERNEL ) ;
if ( ! skb )
return - ENOMEM ;
networking: make skb_put & friends return void pointers
It seems like a historic accident that these return unsigned char *,
and in many places that means casts are required, more often than not.
Make these functions (skb_put, __skb_put and pskb_put) return void *
and remove all the casts across the tree, adding a (u8 *) cast only
where the unsigned char pointer was used directly, all done with the
following spatch:
@@
expression SKB, LEN;
typedef u8;
identifier fn = { skb_put, __skb_put };
@@
- *(fn(SKB, LEN))
+ *(u8 *)fn(SKB, LEN)
@@
expression E, SKB, LEN;
identifier fn = { skb_put, __skb_put };
type T;
@@
- E = ((T *)(fn(SKB, LEN)))
+ E = fn(SKB, LEN)
which actually doesn't cover pskb_put since there are only three
users overall.
A handful of stragglers were converted manually, notably a macro in
drivers/isdn/i4l/isdn_bsdcomp.c and, oddly enough, one of the many
instances in net/bluetooth/hci_sock.c. In the former file, I also
had to fix one whitespace problem spatch introduced.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:21 +03:00
hdr = skb_put ( skb , sizeof ( * hdr ) ) ;
2015-03-17 14:48:48 +03:00
hdr - > opcode = cpu_to_le16 ( MGMT_EV_CMD_STATUS ) ;
hdr - > index = cpu_to_le16 ( index ) ;
hdr - > len = cpu_to_le16 ( sizeof ( * ev ) ) ;
networking: make skb_put & friends return void pointers
It seems like a historic accident that these return unsigned char *,
and in many places that means casts are required, more often than not.
Make these functions (skb_put, __skb_put and pskb_put) return void *
and remove all the casts across the tree, adding a (u8 *) cast only
where the unsigned char pointer was used directly, all done with the
following spatch:
@@
expression SKB, LEN;
typedef u8;
identifier fn = { skb_put, __skb_put };
@@
- *(fn(SKB, LEN))
+ *(u8 *)fn(SKB, LEN)
@@
expression E, SKB, LEN;
identifier fn = { skb_put, __skb_put };
type T;
@@
- E = ((T *)(fn(SKB, LEN)))
+ E = fn(SKB, LEN)
which actually doesn't cover pskb_put since there are only three
users overall.
A handful of stragglers were converted manually, notably a macro in
drivers/isdn/i4l/isdn_bsdcomp.c and, oddly enough, one of the many
instances in net/bluetooth/hci_sock.c. In the former file, I also
had to fix one whitespace problem spatch introduced.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:21 +03:00
ev = skb_put ( skb , sizeof ( * ev ) ) ;
2015-03-17 14:48:48 +03:00
ev - > status = status ;
ev - > opcode = cpu_to_le16 ( cmd ) ;
2016-08-27 21:23:41 +03:00
mskb = create_monitor_ctrl_event ( hdr - > index , hci_sock_get_cookie ( sk ) ,
MGMT_EV_CMD_STATUS , sizeof ( * ev ) , ev ) ;
if ( mskb )
skb - > tstamp = mskb - > tstamp ;
else
__net_timestamp ( skb ) ;
2015-03-17 14:48:48 +03:00
err = sock_queue_rcv_skb ( sk , skb ) ;
if ( err < 0 )
kfree_skb ( skb ) ;
2016-08-27 21:23:41 +03:00
if ( mskb ) {
hci_send_to_channel ( HCI_CHANNEL_MONITOR , mskb ,
HCI_SOCK_TRUSTED , NULL ) ;
kfree_skb ( mskb ) ;
}
2015-03-17 14:48:48 +03:00
return err ;
}
int mgmt_cmd_complete ( struct sock * sk , u16 index , u16 cmd , u8 status ,
void * rp , size_t rp_len )
{
2016-08-27 21:23:41 +03:00
struct sk_buff * skb , * mskb ;
2015-03-17 14:48:48 +03:00
struct mgmt_hdr * hdr ;
struct mgmt_ev_cmd_complete * ev ;
int err ;
BT_DBG ( " sock %p " , sk ) ;
skb = alloc_skb ( sizeof ( * hdr ) + sizeof ( * ev ) + rp_len , GFP_KERNEL ) ;
if ( ! skb )
return - ENOMEM ;
networking: make skb_put & friends return void pointers
It seems like a historic accident that these return unsigned char *,
and in many places that means casts are required, more often than not.
Make these functions (skb_put, __skb_put and pskb_put) return void *
and remove all the casts across the tree, adding a (u8 *) cast only
where the unsigned char pointer was used directly, all done with the
following spatch:
@@
expression SKB, LEN;
typedef u8;
identifier fn = { skb_put, __skb_put };
@@
- *(fn(SKB, LEN))
+ *(u8 *)fn(SKB, LEN)
@@
expression E, SKB, LEN;
identifier fn = { skb_put, __skb_put };
type T;
@@
- E = ((T *)(fn(SKB, LEN)))
+ E = fn(SKB, LEN)
which actually doesn't cover pskb_put since there are only three
users overall.
A handful of stragglers were converted manually, notably a macro in
drivers/isdn/i4l/isdn_bsdcomp.c and, oddly enough, one of the many
instances in net/bluetooth/hci_sock.c. In the former file, I also
had to fix one whitespace problem spatch introduced.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:21 +03:00
hdr = skb_put ( skb , sizeof ( * hdr ) ) ;
2015-03-17 14:48:48 +03:00
hdr - > opcode = cpu_to_le16 ( MGMT_EV_CMD_COMPLETE ) ;
hdr - > index = cpu_to_le16 ( index ) ;
hdr - > len = cpu_to_le16 ( sizeof ( * ev ) + rp_len ) ;
networking: make skb_put & friends return void pointers
It seems like a historic accident that these return unsigned char *,
and in many places that means casts are required, more often than not.
Make these functions (skb_put, __skb_put and pskb_put) return void *
and remove all the casts across the tree, adding a (u8 *) cast only
where the unsigned char pointer was used directly, all done with the
following spatch:
@@
expression SKB, LEN;
typedef u8;
identifier fn = { skb_put, __skb_put };
@@
- *(fn(SKB, LEN))
+ *(u8 *)fn(SKB, LEN)
@@
expression E, SKB, LEN;
identifier fn = { skb_put, __skb_put };
type T;
@@
- E = ((T *)(fn(SKB, LEN)))
+ E = fn(SKB, LEN)
which actually doesn't cover pskb_put since there are only three
users overall.
A handful of stragglers were converted manually, notably a macro in
drivers/isdn/i4l/isdn_bsdcomp.c and, oddly enough, one of the many
instances in net/bluetooth/hci_sock.c. In the former file, I also
had to fix one whitespace problem spatch introduced.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:21 +03:00
ev = skb_put ( skb , sizeof ( * ev ) + rp_len ) ;
2015-03-17 14:48:48 +03:00
ev - > opcode = cpu_to_le16 ( cmd ) ;
ev - > status = status ;
if ( rp )
memcpy ( ev - > data , rp , rp_len ) ;
2016-08-27 21:23:41 +03:00
mskb = create_monitor_ctrl_event ( hdr - > index , hci_sock_get_cookie ( sk ) ,
MGMT_EV_CMD_COMPLETE ,
sizeof ( * ev ) + rp_len , ev ) ;
if ( mskb )
skb - > tstamp = mskb - > tstamp ;
else
__net_timestamp ( skb ) ;
2015-03-17 14:48:48 +03:00
err = sock_queue_rcv_skb ( sk , skb ) ;
if ( err < 0 )
kfree_skb ( skb ) ;
2016-08-27 21:23:41 +03:00
if ( mskb ) {
hci_send_to_channel ( HCI_CHANNEL_MONITOR , mskb ,
HCI_SOCK_TRUSTED , NULL ) ;
kfree_skb ( mskb ) ;
}
2015-03-17 14:48:48 +03:00
return err ;
}
struct mgmt_pending_cmd * mgmt_pending_find ( unsigned short channel , u16 opcode ,
struct hci_dev * hdev )
{
struct mgmt_pending_cmd * cmd ;
list_for_each_entry ( cmd , & hdev - > mgmt_pending , list ) {
if ( hci_sock_get_channel ( cmd - > sk ) ! = channel )
continue ;
if ( cmd - > opcode = = opcode )
return cmd ;
}
return NULL ;
}
struct mgmt_pending_cmd * mgmt_pending_find_data ( unsigned short channel ,
u16 opcode ,
struct hci_dev * hdev ,
const void * data )
{
struct mgmt_pending_cmd * cmd ;
list_for_each_entry ( cmd , & hdev - > mgmt_pending , list ) {
if ( cmd - > user_data ! = data )
continue ;
if ( cmd - > opcode = = opcode )
return cmd ;
}
return NULL ;
}
void mgmt_pending_foreach ( u16 opcode , struct hci_dev * hdev ,
void ( * cb ) ( struct mgmt_pending_cmd * cmd , void * data ) ,
void * data )
{
struct mgmt_pending_cmd * cmd , * tmp ;
list_for_each_entry_safe ( cmd , tmp , & hdev - > mgmt_pending , list ) {
if ( opcode > 0 & & cmd - > opcode ! = opcode )
continue ;
cb ( cmd , data ) ;
}
}
Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 1
This make use of hci_cmd_sync_queue for the following MGMT commands:
Set Device Class
Set Device ID
Add UUID
Remove UUID
tools/mgmt-tester -s "Set Device Class"
Test Summary
------------
Set Device Class - Success 1 Passed
Set Device Class - Success 2 Passed
Set Device Class - Invalid parameters 1 Passed
Total: 3, Passed: 3 (100.0%), Failed: 0, Not Run: 0
Overall execution time: 0.0599 seconds
tools/mgmt-tester -s "Set Device ID"
Test Summary
------------
Set Device ID - Success 1 Passed
Set Device ID - Success 2 Passed
Set Device ID - Disable Passed
Set Device ID - Power off and Power on Passed
Set Device ID - SSP off and Power on Passed
Set Device ID - Invalid Parameter Passed
Total: 6, Passed: 6 (100.0%), Failed: 0, Not Run: 0
Overall execution time: 0.107 seconds
tools/mgmt-tester -s "Add UUID"
Test Summary
------------
Add UUID - UUID-16 1 Passed
Add UUID - UUID-16 multiple 1 Passed
Add UUID - UUID-16 partial 1 Passed
Add UUID - UUID-32 1 Passed
Add UUID - UUID-32 multiple 1 Passed
Add UUID - UUID-32 partial 1 Passed
Add UUID - UUID-128 1 Passed
Add UUID - UUID-128 multiple 1 Passed
Add UUID - UUID-128 partial 1 Passed
Add UUID - UUID mix Passed
Total: 10, Passed: 10 (100.0%), Failed: 0, Not Run: 0
Overall execution time: 0.198 seconds
tools/mgmt-tester -s "Remove UUID"
Test Summary
------------
Remove UUID - Success 1 Passed
Remove UUID - All UUID - Success 2 Passed
Remove UUID - Power Off - Success 3 Passed
Remove UUID - Power Off and On - Success 4 Passed
Remove UUID - Not Exist - Invalid Params 1 Passed
Total: 5, Passed: 5 (100.0%), Failed: 0, Not Run: 0
Overall execution time: 0.0908 seconds
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
2021-10-28 02:58:39 +03:00
struct mgmt_pending_cmd * mgmt_pending_new ( struct sock * sk , u16 opcode ,
2015-03-17 14:48:48 +03:00
struct hci_dev * hdev ,
void * data , u16 len )
{
struct mgmt_pending_cmd * cmd ;
cmd = kzalloc ( sizeof ( * cmd ) , GFP_KERNEL ) ;
if ( ! cmd )
return NULL ;
cmd - > opcode = opcode ;
cmd - > index = hdev - > id ;
cmd - > param = kmemdup ( data , len , GFP_KERNEL ) ;
if ( ! cmd - > param ) {
kfree ( cmd ) ;
return NULL ;
}
cmd - > param_len = len ;
cmd - > sk = sk ;
sock_hold ( sk ) ;
Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 1
This make use of hci_cmd_sync_queue for the following MGMT commands:
Set Device Class
Set Device ID
Add UUID
Remove UUID
tools/mgmt-tester -s "Set Device Class"
Test Summary
------------
Set Device Class - Success 1 Passed
Set Device Class - Success 2 Passed
Set Device Class - Invalid parameters 1 Passed
Total: 3, Passed: 3 (100.0%), Failed: 0, Not Run: 0
Overall execution time: 0.0599 seconds
tools/mgmt-tester -s "Set Device ID"
Test Summary
------------
Set Device ID - Success 1 Passed
Set Device ID - Success 2 Passed
Set Device ID - Disable Passed
Set Device ID - Power off and Power on Passed
Set Device ID - SSP off and Power on Passed
Set Device ID - Invalid Parameter Passed
Total: 6, Passed: 6 (100.0%), Failed: 0, Not Run: 0
Overall execution time: 0.107 seconds
tools/mgmt-tester -s "Add UUID"
Test Summary
------------
Add UUID - UUID-16 1 Passed
Add UUID - UUID-16 multiple 1 Passed
Add UUID - UUID-16 partial 1 Passed
Add UUID - UUID-32 1 Passed
Add UUID - UUID-32 multiple 1 Passed
Add UUID - UUID-32 partial 1 Passed
Add UUID - UUID-128 1 Passed
Add UUID - UUID-128 multiple 1 Passed
Add UUID - UUID-128 partial 1 Passed
Add UUID - UUID mix Passed
Total: 10, Passed: 10 (100.0%), Failed: 0, Not Run: 0
Overall execution time: 0.198 seconds
tools/mgmt-tester -s "Remove UUID"
Test Summary
------------
Remove UUID - Success 1 Passed
Remove UUID - All UUID - Success 2 Passed
Remove UUID - Power Off - Success 3 Passed
Remove UUID - Power Off and On - Success 4 Passed
Remove UUID - Not Exist - Invalid Params 1 Passed
Total: 5, Passed: 5 (100.0%), Failed: 0, Not Run: 0
Overall execution time: 0.0908 seconds
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
2021-10-28 02:58:39 +03:00
return cmd ;
}
struct mgmt_pending_cmd * mgmt_pending_add ( struct sock * sk , u16 opcode ,
struct hci_dev * hdev ,
void * data , u16 len )
{
struct mgmt_pending_cmd * cmd ;
cmd = mgmt_pending_new ( sk , opcode , hdev , data , len ) ;
if ( ! cmd )
return NULL ;
2022-03-31 21:07:47 +03:00
list_add_tail ( & cmd - > list , & hdev - > mgmt_pending ) ;
2015-03-17 14:48:48 +03:00
return cmd ;
}
void mgmt_pending_free ( struct mgmt_pending_cmd * cmd )
{
sock_put ( cmd - > sk ) ;
kfree ( cmd - > param ) ;
kfree ( cmd ) ;
}
void mgmt_pending_remove ( struct mgmt_pending_cmd * cmd )
{
list_del ( & cmd - > list ) ;
mgmt_pending_free ( cmd ) ;
}
2022-09-01 22:19:13 +03:00
void mgmt_mesh_foreach ( struct hci_dev * hdev ,
void ( * cb ) ( struct mgmt_mesh_tx * mesh_tx , void * data ) ,
void * data , struct sock * sk )
{
struct mgmt_mesh_tx * mesh_tx , * tmp ;
list_for_each_entry_safe ( mesh_tx , tmp , & hdev - > mgmt_pending , list ) {
if ( ! sk | | mesh_tx - > sk = = sk )
cb ( mesh_tx , data ) ;
}
}
struct mgmt_mesh_tx * mgmt_mesh_next ( struct hci_dev * hdev , struct sock * sk )
{
struct mgmt_mesh_tx * mesh_tx ;
if ( list_empty ( & hdev - > mesh_pending ) )
return NULL ;
list_for_each_entry ( mesh_tx , & hdev - > mesh_pending , list ) {
if ( ! sk | | mesh_tx - > sk = = sk )
return mesh_tx ;
}
return NULL ;
}
struct mgmt_mesh_tx * mgmt_mesh_find ( struct hci_dev * hdev , u8 handle )
{
struct mgmt_mesh_tx * mesh_tx ;
if ( list_empty ( & hdev - > mesh_pending ) )
return NULL ;
list_for_each_entry ( mesh_tx , & hdev - > mesh_pending , list ) {
if ( mesh_tx - > handle = = handle )
return mesh_tx ;
}
return NULL ;
}
struct mgmt_mesh_tx * mgmt_mesh_add ( struct sock * sk , struct hci_dev * hdev ,
void * data , u16 len )
{
struct mgmt_mesh_tx * mesh_tx ;
mesh_tx = kzalloc ( sizeof ( * mesh_tx ) , GFP_KERNEL ) ;
if ( ! mesh_tx )
return NULL ;
hdev - > mesh_send_ref + + ;
if ( ! hdev - > mesh_send_ref )
hdev - > mesh_send_ref + + ;
mesh_tx - > handle = hdev - > mesh_send_ref ;
mesh_tx - > index = hdev - > id ;
memcpy ( mesh_tx - > param , data , len ) ;
mesh_tx - > param_len = len ;
mesh_tx - > sk = sk ;
sock_hold ( sk ) ;
list_add_tail ( & mesh_tx - > list , & hdev - > mesh_pending ) ;
return mesh_tx ;
}
void mgmt_mesh_remove ( struct mgmt_mesh_tx * mesh_tx )
{
list_del ( & mesh_tx - > list ) ;
sock_put ( mesh_tx - > sk ) ;
kfree ( mesh_tx ) ;
}