2005-04-17 02:20:36 +04:00
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright ( C ) 2000 - 2001 Qualcomm Incorporated
Written 2000 , 2001 by Maxim Krasnyansky < maxk @ qualcomm . com >
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 .
*/
# ifndef __HCI_CORE_H
# define __HCI_CORE_H
# include <net/bluetooth/hci.h>
/* HCI upper protocols */
# define HCI_PROTO_L2CAP 0
# define HCI_PROTO_SCO 1
/* HCI Core structures */
struct inquiry_data {
bdaddr_t bdaddr ;
__u8 pscan_rep_mode ;
__u8 pscan_period_mode ;
__u8 pscan_mode ;
__u8 dev_class [ 3 ] ;
2005-11-08 20:57:21 +03:00
__le16 clock_offset ;
2005-04-17 02:20:36 +04:00
__s8 rssi ;
2008-07-14 22:13:48 +04:00
__u8 ssp_mode ;
2005-04-17 02:20:36 +04:00
} ;
struct inquiry_entry {
struct inquiry_entry * next ;
__u32 timestamp ;
struct inquiry_data data ;
} ;
struct inquiry_cache {
spinlock_t lock ;
__u32 timestamp ;
struct inquiry_entry * list ;
} ;
struct hci_conn_hash {
struct list_head list ;
spinlock_t lock ;
unsigned int acl_num ;
unsigned int sco_num ;
} ;
struct hci_dev {
struct list_head list ;
spinlock_t lock ;
atomic_t refcnt ;
char name [ 8 ] ;
unsigned long flags ;
__u16 id ;
__u8 type ;
bdaddr_t bdaddr ;
2007-10-20 15:33:56 +04:00
__u8 dev_name [ 248 ] ;
__u8 dev_class [ 3 ] ;
2005-04-17 02:20:36 +04:00
__u8 features [ 8 ] ;
2007-10-20 15:33:56 +04:00
__u8 commands [ 64 ] ;
2008-07-14 22:13:48 +04:00
__u8 ssp_mode ;
2006-09-23 11:57:20 +04:00
__u8 hci_ver ;
__u16 hci_rev ;
__u16 manufacturer ;
2005-04-17 02:20:36 +04:00
__u16 voice_setting ;
__u16 pkt_type ;
2007-07-11 11:51:55 +04:00
__u16 esco_type ;
2005-04-17 02:20:36 +04:00
__u16 link_policy ;
__u16 link_mode ;
2006-07-03 12:02:33 +04:00
__u32 idle_timeout ;
__u16 sniff_min_interval ;
__u16 sniff_max_interval ;
2005-04-17 02:20:36 +04:00
unsigned long quirks ;
atomic_t cmd_cnt ;
unsigned int acl_cnt ;
unsigned int sco_cnt ;
unsigned int acl_mtu ;
unsigned int sco_mtu ;
unsigned int acl_pkts ;
unsigned int sco_pkts ;
unsigned long cmd_last_tx ;
unsigned long acl_last_tx ;
unsigned long sco_last_tx ;
struct tasklet_struct cmd_task ;
struct tasklet_struct rx_task ;
struct tasklet_struct tx_task ;
struct sk_buff_head rx_q ;
struct sk_buff_head raw_q ;
struct sk_buff_head cmd_q ;
struct sk_buff * sent_cmd ;
2007-07-11 08:42:04 +04:00
struct sk_buff * reassembly [ 3 ] ;
2005-04-17 02:20:36 +04:00
2009-07-26 12:18:19 +04:00
struct mutex req_lock ;
2005-04-17 02:20:36 +04:00
wait_queue_head_t req_wait_q ;
__u32 req_status ;
__u32 req_result ;
struct inquiry_cache inq_cache ;
struct hci_conn_hash conn_hash ;
struct hci_dev_stats stat ;
struct sk_buff_head driver_init ;
void * driver_data ;
void * core_data ;
atomic_t promisc ;
2006-07-03 12:02:41 +04:00
struct device * parent ;
struct device dev ;
2005-04-17 02:20:36 +04:00
2009-06-08 16:41:38 +04:00
struct rfkill * rfkill ;
2005-04-17 02:20:36 +04:00
struct module * owner ;
int ( * open ) ( struct hci_dev * hdev ) ;
int ( * close ) ( struct hci_dev * hdev ) ;
int ( * flush ) ( struct hci_dev * hdev ) ;
int ( * send ) ( struct sk_buff * skb ) ;
void ( * destruct ) ( struct hci_dev * hdev ) ;
void ( * notify ) ( struct hci_dev * hdev , unsigned int evt ) ;
int ( * ioctl ) ( struct hci_dev * hdev , unsigned int cmd , unsigned long arg ) ;
} ;
struct hci_conn {
struct list_head list ;
atomic_t refcnt ;
spinlock_t lock ;
bdaddr_t dst ;
__u16 handle ;
__u16 state ;
2006-07-03 12:02:33 +04:00
__u8 mode ;
2005-04-17 02:20:36 +04:00
__u8 type ;
__u8 out ;
2006-10-15 19:30:56 +04:00
__u8 attempt ;
2005-04-17 02:20:36 +04:00
__u8 dev_class [ 3 ] ;
2006-07-03 12:02:33 +04:00
__u8 features [ 8 ] ;
2008-07-14 22:13:48 +04:00
__u8 ssp_mode ;
2006-07-03 12:02:33 +04:00
__u16 interval ;
2008-07-14 22:13:46 +04:00
__u16 pkt_type ;
2006-07-03 12:02:33 +04:00
__u16 link_policy ;
2005-04-17 02:20:36 +04:00
__u32 link_mode ;
2008-07-14 22:13:50 +04:00
__u8 auth_type ;
2009-01-15 23:58:04 +03:00
__u8 sec_level ;
2006-07-03 12:02:33 +04:00
__u8 power_save ;
2009-04-26 22:01:22 +04:00
__u16 disc_timeout ;
2005-04-17 02:20:36 +04:00
unsigned long pend ;
2006-07-03 12:02:33 +04:00
2005-04-17 02:20:36 +04:00
unsigned int sent ;
2006-07-03 12:02:33 +04:00
2005-04-17 02:20:36 +04:00
struct sk_buff_head data_q ;
2006-07-03 12:02:33 +04:00
struct timer_list disc_timer ;
struct timer_list idle_timer ;
2009-04-23 15:50:54 +04:00
struct work_struct work_add ;
struct work_struct work_del ;
2006-07-06 14:38:46 +04:00
struct device dev ;
2009-08-23 01:19:26 +04:00
atomic_t devref ;
2006-07-06 14:38:46 +04:00
2005-04-17 02:20:36 +04:00
struct hci_dev * hdev ;
void * l2cap_data ;
void * sco_data ;
void * priv ;
struct hci_conn * link ;
} ;
extern struct hci_proto * hci_proto [ ] ;
extern struct list_head hci_dev_list ;
extern struct list_head hci_cb_list ;
extern rwlock_t hci_dev_list_lock ;
extern rwlock_t hci_cb_list_lock ;
/* ----- Inquiry cache ----- */
# define INQUIRY_CACHE_AGE_MAX (HZ*30) // 30 seconds
# define INQUIRY_ENTRY_AGE_MAX (HZ*60) // 60 seconds
# define inquiry_cache_lock(c) spin_lock(&c->lock)
# define inquiry_cache_unlock(c) spin_unlock(&c->lock)
# define inquiry_cache_lock_bh(c) spin_lock_bh(&c->lock)
# define inquiry_cache_unlock_bh(c) spin_unlock_bh(&c->lock)
static inline void inquiry_cache_init ( struct hci_dev * hdev )
{
struct inquiry_cache * c = & hdev - > inq_cache ;
spin_lock_init ( & c - > lock ) ;
c - > list = NULL ;
}
static inline int inquiry_cache_empty ( struct hci_dev * hdev )
{
struct inquiry_cache * c = & hdev - > inq_cache ;
return ( c - > list = = NULL ) ;
}
static inline long inquiry_cache_age ( struct hci_dev * hdev )
{
struct inquiry_cache * c = & hdev - > inq_cache ;
return jiffies - c - > timestamp ;
}
static inline long inquiry_entry_age ( struct inquiry_entry * e )
{
return jiffies - e - > timestamp ;
}
struct inquiry_entry * hci_inquiry_cache_lookup ( struct hci_dev * hdev , bdaddr_t * bdaddr ) ;
void hci_inquiry_cache_update ( struct hci_dev * hdev , struct inquiry_data * data ) ;
/* ----- HCI Connections ----- */
enum {
HCI_CONN_AUTH_PEND ,
HCI_CONN_ENCRYPT_PEND ,
2006-07-03 12:02:33 +04:00
HCI_CONN_RSWITCH_PEND ,
HCI_CONN_MODE_CHANGE_PEND ,
2005-04-17 02:20:36 +04:00
} ;
static inline void hci_conn_hash_init ( struct hci_dev * hdev )
{
struct hci_conn_hash * h = & hdev - > conn_hash ;
INIT_LIST_HEAD ( & h - > list ) ;
spin_lock_init ( & h - > lock ) ;
h - > acl_num = 0 ;
h - > sco_num = 0 ;
}
static inline void hci_conn_hash_add ( struct hci_dev * hdev , struct hci_conn * c )
{
struct hci_conn_hash * h = & hdev - > conn_hash ;
list_add ( & c - > list , & h - > list ) ;
if ( c - > type = = ACL_LINK )
h - > acl_num + + ;
else
h - > sco_num + + ;
}
static inline void hci_conn_hash_del ( struct hci_dev * hdev , struct hci_conn * c )
{
struct hci_conn_hash * h = & hdev - > conn_hash ;
list_del ( & c - > list ) ;
if ( c - > type = = ACL_LINK )
h - > acl_num - - ;
else
h - > sco_num - - ;
}
static inline struct hci_conn * hci_conn_hash_lookup_handle ( struct hci_dev * hdev ,
__u16 handle )
{
struct hci_conn_hash * h = & hdev - > conn_hash ;
struct list_head * p ;
struct hci_conn * c ;
list_for_each ( p , & h - > list ) {
c = list_entry ( p , struct hci_conn , list ) ;
if ( c - > handle = = handle )
return c ;
}
return NULL ;
}
static inline struct hci_conn * hci_conn_hash_lookup_ba ( struct hci_dev * hdev ,
__u8 type , bdaddr_t * ba )
{
struct hci_conn_hash * h = & hdev - > conn_hash ;
struct list_head * p ;
struct hci_conn * c ;
list_for_each ( p , & h - > list ) {
c = list_entry ( p , struct hci_conn , list ) ;
if ( c - > type = = type & & ! bacmp ( & c - > dst , ba ) )
return c ;
}
return NULL ;
}
2006-10-15 19:30:56 +04:00
static inline struct hci_conn * hci_conn_hash_lookup_state ( struct hci_dev * hdev ,
__u8 type , __u16 state )
{
struct hci_conn_hash * h = & hdev - > conn_hash ;
struct list_head * p ;
struct hci_conn * c ;
list_for_each ( p , & h - > list ) {
c = list_entry ( p , struct hci_conn , list ) ;
if ( c - > type = = type & & c - > state = = state )
return c ;
}
return NULL ;
}
void hci_acl_connect ( struct hci_conn * conn ) ;
2005-04-17 02:20:36 +04:00
void hci_acl_disconn ( struct hci_conn * conn , __u8 reason ) ;
void hci_add_sco ( struct hci_conn * conn , __u16 handle ) ;
2007-10-20 16:55:10 +04:00
void hci_setup_sync ( struct hci_conn * conn , __u16 handle ) ;
2005-04-17 02:20:36 +04:00
struct hci_conn * hci_conn_add ( struct hci_dev * hdev , int type , bdaddr_t * dst ) ;
2007-10-20 15:33:56 +04:00
int hci_conn_del ( struct hci_conn * conn ) ;
void hci_conn_hash_flush ( struct hci_dev * hdev ) ;
void hci_conn_check_pending ( struct hci_dev * hdev ) ;
2005-04-17 02:20:36 +04:00
2009-01-15 23:58:04 +03:00
struct hci_conn * hci_connect ( struct hci_dev * hdev , int type , bdaddr_t * dst , __u8 sec_level , __u8 auth_type ) ;
2008-09-09 09:19:20 +04:00
int hci_conn_check_link_mode ( struct hci_conn * conn ) ;
2009-02-09 04:48:38 +03:00
int hci_conn_security ( struct hci_conn * conn , __u8 sec_level , __u8 auth_type ) ;
2005-04-17 02:20:36 +04:00
int hci_conn_change_link_key ( struct hci_conn * conn ) ;
2009-01-15 23:58:04 +03:00
int hci_conn_switch_role ( struct hci_conn * conn , __u8 role ) ;
2005-04-17 02:20:36 +04:00
2006-07-03 12:02:33 +04:00
void hci_conn_enter_active_mode ( struct hci_conn * conn ) ;
void hci_conn_enter_sniff_mode ( struct hci_conn * conn ) ;
2005-04-17 02:20:36 +04:00
2009-08-23 01:19:26 +04:00
void hci_conn_hold_device ( struct hci_conn * conn ) ;
void hci_conn_put_device ( struct hci_conn * conn ) ;
2005-04-17 02:20:36 +04:00
static inline void hci_conn_hold ( struct hci_conn * conn )
{
atomic_inc ( & conn - > refcnt ) ;
2006-07-03 12:02:33 +04:00
del_timer ( & conn - > disc_timer ) ;
2005-04-17 02:20:36 +04:00
}
static inline void hci_conn_put ( struct hci_conn * conn )
{
if ( atomic_dec_and_test ( & conn - > refcnt ) ) {
2006-07-03 12:02:33 +04:00
unsigned long timeo ;
2005-04-17 02:20:36 +04:00
if ( conn - > type = = ACL_LINK ) {
2006-07-03 12:02:33 +04:00
del_timer ( & conn - > idle_timer ) ;
2006-09-26 11:43:48 +04:00
if ( conn - > state = = BT_CONNECTED ) {
2009-04-26 22:01:22 +04:00
timeo = msecs_to_jiffies ( conn - > disc_timeout ) ;
2006-09-26 11:43:48 +04:00
if ( ! conn - > out )
2009-04-26 22:01:22 +04:00
timeo * = 2 ;
2006-09-26 11:43:48 +04:00
} else
timeo = msecs_to_jiffies ( 10 ) ;
2005-04-17 02:20:36 +04:00
} else
2006-07-03 12:02:33 +04:00
timeo = msecs_to_jiffies ( 10 ) ;
mod_timer ( & conn - > disc_timer , jiffies + timeo ) ;
2005-04-17 02:20:36 +04:00
}
}
/* ----- HCI tasks ----- */
static inline void hci_sched_cmd ( struct hci_dev * hdev )
{
tasklet_schedule ( & hdev - > cmd_task ) ;
}
static inline void hci_sched_rx ( struct hci_dev * hdev )
{
tasklet_schedule ( & hdev - > rx_task ) ;
}
static inline void hci_sched_tx ( struct hci_dev * hdev )
{
tasklet_schedule ( & hdev - > tx_task ) ;
}
/* ----- HCI Devices ----- */
static inline void __hci_dev_put ( struct hci_dev * d )
{
if ( atomic_dec_and_test ( & d - > refcnt ) )
d - > destruct ( d ) ;
}
static inline void hci_dev_put ( struct hci_dev * d )
{
__hci_dev_put ( d ) ;
module_put ( d - > owner ) ;
}
static inline struct hci_dev * __hci_dev_hold ( struct hci_dev * d )
{
atomic_inc ( & d - > refcnt ) ;
return d ;
}
static inline struct hci_dev * hci_dev_hold ( struct hci_dev * d )
{
if ( try_module_get ( d - > owner ) )
return __hci_dev_hold ( d ) ;
return NULL ;
}
# define hci_dev_lock(d) spin_lock(&d->lock)
# define hci_dev_unlock(d) spin_unlock(&d->lock)
# define hci_dev_lock_bh(d) spin_lock_bh(&d->lock)
# define hci_dev_unlock_bh(d) spin_unlock_bh(&d->lock)
struct hci_dev * hci_dev_get ( int index ) ;
struct hci_dev * hci_get_route ( bdaddr_t * src , bdaddr_t * dst ) ;
struct hci_dev * hci_alloc_dev ( void ) ;
void hci_free_dev ( struct hci_dev * hdev ) ;
int hci_register_dev ( struct hci_dev * hdev ) ;
int hci_unregister_dev ( struct hci_dev * hdev ) ;
int hci_suspend_dev ( struct hci_dev * hdev ) ;
int hci_resume_dev ( struct hci_dev * hdev ) ;
int hci_dev_open ( __u16 dev ) ;
int hci_dev_close ( __u16 dev ) ;
int hci_dev_reset ( __u16 dev ) ;
int hci_dev_reset_stat ( __u16 dev ) ;
int hci_dev_cmd ( unsigned int cmd , void __user * arg ) ;
int hci_get_dev_list ( void __user * arg ) ;
int hci_get_dev_info ( void __user * arg ) ;
int hci_get_conn_list ( void __user * arg ) ;
int hci_get_conn_info ( struct hci_dev * hdev , void __user * arg ) ;
2008-07-14 22:13:50 +04:00
int hci_get_auth_info ( struct hci_dev * hdev , void __user * arg ) ;
2005-04-17 02:20:36 +04:00
int hci_inquiry ( void __user * arg ) ;
void hci_event_packet ( struct hci_dev * hdev , struct sk_buff * skb ) ;
/* Receive frame from HCI drivers */
static inline int hci_recv_frame ( struct sk_buff * skb )
{
struct hci_dev * hdev = ( struct hci_dev * ) skb - > dev ;
if ( ! hdev | | ( ! test_bit ( HCI_UP , & hdev - > flags )
& & ! test_bit ( HCI_INIT , & hdev - > flags ) ) ) {
kfree_skb ( skb ) ;
return - ENXIO ;
}
/* Incomming skb */
bt_cb ( skb ) - > incoming = 1 ;
/* Time stamp */
2005-08-15 04:24:31 +04:00
__net_timestamp ( skb ) ;
2005-04-17 02:20:36 +04:00
/* Queue frame for rx task */
skb_queue_tail ( & hdev - > rx_q , skb ) ;
hci_sched_rx ( hdev ) ;
return 0 ;
}
2007-07-11 08:42:04 +04:00
int hci_recv_fragment ( struct hci_dev * hdev , int type , void * data , int count ) ;
2005-04-17 02:20:36 +04:00
int hci_register_sysfs ( struct hci_dev * hdev ) ;
void hci_unregister_sysfs ( struct hci_dev * hdev ) ;
2009-05-03 05:24:06 +04:00
void hci_conn_init_sysfs ( struct hci_conn * conn ) ;
2006-07-06 14:38:46 +04:00
void hci_conn_add_sysfs ( struct hci_conn * conn ) ;
void hci_conn_del_sysfs ( struct hci_conn * conn ) ;
2005-04-17 02:20:36 +04:00
2006-07-03 12:02:41 +04:00
# define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev))
2005-04-17 02:20:36 +04:00
/* ----- LMP capabilities ----- */
2006-07-03 12:02:33 +04:00
# define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH)
# define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT)
# define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF)
# define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
2007-07-11 11:51:55 +04:00
# define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO)
2008-07-14 22:13:49 +04:00
# define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR)
2005-04-17 02:20:36 +04:00
/* ----- HCI protocols ----- */
struct hci_proto {
2009-01-15 23:58:04 +03:00
char * name ;
2005-04-17 02:20:36 +04:00
unsigned int id ;
unsigned long flags ;
void * priv ;
2009-01-15 23:58:04 +03:00
int ( * connect_ind ) ( struct hci_dev * hdev , bdaddr_t * bdaddr , __u8 type ) ;
2005-04-17 02:20:36 +04:00
int ( * connect_cfm ) ( struct hci_conn * conn , __u8 status ) ;
2009-02-12 16:02:50 +03:00
int ( * disconn_ind ) ( struct hci_conn * conn ) ;
int ( * disconn_cfm ) ( struct hci_conn * conn , __u8 reason ) ;
2005-04-17 02:20:36 +04:00
int ( * recv_acldata ) ( struct hci_conn * conn , struct sk_buff * skb , __u16 flags ) ;
int ( * recv_scodata ) ( struct hci_conn * conn , struct sk_buff * skb ) ;
2009-01-15 23:58:04 +03:00
int ( * security_cfm ) ( struct hci_conn * conn , __u8 status , __u8 encrypt ) ;
2005-04-17 02:20:36 +04:00
} ;
static inline int hci_proto_connect_ind ( struct hci_dev * hdev , bdaddr_t * bdaddr , __u8 type )
{
register struct hci_proto * hp ;
int mask = 0 ;
2009-01-15 23:58:04 +03:00
2005-04-17 02:20:36 +04:00
hp = hci_proto [ HCI_PROTO_L2CAP ] ;
if ( hp & & hp - > connect_ind )
mask | = hp - > connect_ind ( hdev , bdaddr , type ) ;
hp = hci_proto [ HCI_PROTO_SCO ] ;
if ( hp & & hp - > connect_ind )
mask | = hp - > connect_ind ( hdev , bdaddr , type ) ;
return mask ;
}
static inline void hci_proto_connect_cfm ( struct hci_conn * conn , __u8 status )
{
register struct hci_proto * hp ;
hp = hci_proto [ HCI_PROTO_L2CAP ] ;
if ( hp & & hp - > connect_cfm )
hp - > connect_cfm ( conn , status ) ;
hp = hci_proto [ HCI_PROTO_SCO ] ;
if ( hp & & hp - > connect_cfm )
hp - > connect_cfm ( conn , status ) ;
}
2009-02-12 16:02:50 +03:00
static inline int hci_proto_disconn_ind ( struct hci_conn * conn )
2005-04-17 02:20:36 +04:00
{
register struct hci_proto * hp ;
2009-02-12 16:02:50 +03:00
int reason = 0x13 ;
2005-04-17 02:20:36 +04:00
hp = hci_proto [ HCI_PROTO_L2CAP ] ;
if ( hp & & hp - > disconn_ind )
2009-02-12 16:02:50 +03:00
reason = hp - > disconn_ind ( conn ) ;
2005-04-17 02:20:36 +04:00
hp = hci_proto [ HCI_PROTO_SCO ] ;
if ( hp & & hp - > disconn_ind )
2009-02-12 16:02:50 +03:00
reason = hp - > disconn_ind ( conn ) ;
return reason ;
}
static inline void hci_proto_disconn_cfm ( struct hci_conn * conn , __u8 reason )
{
register struct hci_proto * hp ;
hp = hci_proto [ HCI_PROTO_L2CAP ] ;
if ( hp & & hp - > disconn_cfm )
hp - > disconn_cfm ( conn , reason ) ;
hp = hci_proto [ HCI_PROTO_SCO ] ;
if ( hp & & hp - > disconn_cfm )
hp - > disconn_cfm ( conn , reason ) ;
2005-04-17 02:20:36 +04:00
}
static inline void hci_proto_auth_cfm ( struct hci_conn * conn , __u8 status )
{
register struct hci_proto * hp ;
2009-01-15 23:58:04 +03:00
__u8 encrypt ;
if ( test_bit ( HCI_CONN_ENCRYPT_PEND , & conn - > pend ) )
return ;
encrypt = ( conn - > link_mode & HCI_LM_ENCRYPT ) ? 0x01 : 0x00 ;
2005-04-17 02:20:36 +04:00
hp = hci_proto [ HCI_PROTO_L2CAP ] ;
2009-01-15 23:58:04 +03:00
if ( hp & & hp - > security_cfm )
hp - > security_cfm ( conn , status , encrypt ) ;
2005-04-17 02:20:36 +04:00
hp = hci_proto [ HCI_PROTO_SCO ] ;
2009-01-15 23:58:04 +03:00
if ( hp & & hp - > security_cfm )
hp - > security_cfm ( conn , status , encrypt ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-14 22:13:45 +04:00
static inline void hci_proto_encrypt_cfm ( struct hci_conn * conn , __u8 status , __u8 encrypt )
2005-04-17 02:20:36 +04:00
{
register struct hci_proto * hp ;
hp = hci_proto [ HCI_PROTO_L2CAP ] ;
2009-01-15 23:58:04 +03:00
if ( hp & & hp - > security_cfm )
hp - > security_cfm ( conn , status , encrypt ) ;
2005-04-17 02:20:36 +04:00
hp = hci_proto [ HCI_PROTO_SCO ] ;
2009-01-15 23:58:04 +03:00
if ( hp & & hp - > security_cfm )
hp - > security_cfm ( conn , status , encrypt ) ;
2005-04-17 02:20:36 +04:00
}
int hci_register_proto ( struct hci_proto * hproto ) ;
int hci_unregister_proto ( struct hci_proto * hproto ) ;
/* ----- HCI callbacks ----- */
struct hci_cb {
struct list_head list ;
char * name ;
2009-01-15 23:58:04 +03:00
void ( * security_cfm ) ( struct hci_conn * conn , __u8 status , __u8 encrypt ) ;
2005-04-17 02:20:36 +04:00
void ( * key_change_cfm ) ( struct hci_conn * conn , __u8 status ) ;
void ( * role_switch_cfm ) ( struct hci_conn * conn , __u8 status , __u8 role ) ;
} ;
static inline void hci_auth_cfm ( struct hci_conn * conn , __u8 status )
{
struct list_head * p ;
2009-01-15 23:58:04 +03:00
__u8 encrypt ;
2005-04-17 02:20:36 +04:00
hci_proto_auth_cfm ( conn , status ) ;
2009-01-15 23:58:04 +03:00
if ( test_bit ( HCI_CONN_ENCRYPT_PEND , & conn - > pend ) )
return ;
encrypt = ( conn - > link_mode & HCI_LM_ENCRYPT ) ? 0x01 : 0x00 ;
2005-04-17 02:20:36 +04:00
read_lock_bh ( & hci_cb_list_lock ) ;
list_for_each ( p , & hci_cb_list ) {
struct hci_cb * cb = list_entry ( p , struct hci_cb , list ) ;
2009-01-15 23:58:04 +03:00
if ( cb - > security_cfm )
cb - > security_cfm ( conn , status , encrypt ) ;
2005-04-17 02:20:36 +04:00
}
read_unlock_bh ( & hci_cb_list_lock ) ;
}
static inline void hci_encrypt_cfm ( struct hci_conn * conn , __u8 status , __u8 encrypt )
{
struct list_head * p ;
2009-02-09 05:55:28 +03:00
if ( conn - > sec_level = = BT_SECURITY_SDP )
conn - > sec_level = BT_SECURITY_LOW ;
2008-07-14 22:13:45 +04:00
hci_proto_encrypt_cfm ( conn , status , encrypt ) ;
2005-04-17 02:20:36 +04:00
read_lock_bh ( & hci_cb_list_lock ) ;
list_for_each ( p , & hci_cb_list ) {
struct hci_cb * cb = list_entry ( p , struct hci_cb , list ) ;
2009-01-15 23:58:04 +03:00
if ( cb - > security_cfm )
cb - > security_cfm ( conn , status , encrypt ) ;
2005-04-17 02:20:36 +04:00
}
read_unlock_bh ( & hci_cb_list_lock ) ;
}
static inline void hci_key_change_cfm ( struct hci_conn * conn , __u8 status )
{
struct list_head * p ;
read_lock_bh ( & hci_cb_list_lock ) ;
list_for_each ( p , & hci_cb_list ) {
struct hci_cb * cb = list_entry ( p , struct hci_cb , list ) ;
if ( cb - > key_change_cfm )
cb - > key_change_cfm ( conn , status ) ;
}
read_unlock_bh ( & hci_cb_list_lock ) ;
}
static inline void hci_role_switch_cfm ( struct hci_conn * conn , __u8 status , __u8 role )
{
struct list_head * p ;
read_lock_bh ( & hci_cb_list_lock ) ;
list_for_each ( p , & hci_cb_list ) {
struct hci_cb * cb = list_entry ( p , struct hci_cb , list ) ;
if ( cb - > role_switch_cfm )
cb - > role_switch_cfm ( conn , status , role ) ;
}
read_unlock_bh ( & hci_cb_list_lock ) ;
}
int hci_register_cb ( struct hci_cb * hcb ) ;
int hci_unregister_cb ( struct hci_cb * hcb ) ;
int hci_register_notifier ( struct notifier_block * nb ) ;
int hci_unregister_notifier ( struct notifier_block * nb ) ;
2007-10-20 15:33:56 +04:00
int hci_send_cmd ( struct hci_dev * hdev , __u16 opcode , __u32 plen , void * param ) ;
2005-04-17 02:20:36 +04:00
int hci_send_acl ( struct hci_conn * conn , struct sk_buff * skb , __u16 flags ) ;
int hci_send_sco ( struct hci_conn * conn , struct sk_buff * skb ) ;
2007-10-20 15:33:56 +04:00
void * hci_sent_cmd_data ( struct hci_dev * hdev , __u16 opcode ) ;
2005-04-17 02:20:36 +04:00
void hci_si_event ( struct hci_dev * hdev , int type , int dlen , void * data ) ;
/* ----- HCI Sockets ----- */
void hci_send_to_sock ( struct hci_dev * hdev , struct sk_buff * skb ) ;
/* HCI info for socket */
# define hci_pi(sk) ((struct hci_pinfo *) sk)
struct hci_pinfo {
struct bt_sock bt ;
struct hci_dev * hdev ;
struct hci_filter filter ;
__u32 cmsg_mask ;
} ;
/* HCI security filter */
# define HCI_SFLT_MAX_OGF 5
struct hci_sec_filter {
__u32 type_mask ;
__u32 event_mask [ 2 ] ;
__u32 ocf_mask [ HCI_SFLT_MAX_OGF + 1 ] [ 4 ] ;
} ;
/* ----- HCI requests ----- */
# define HCI_REQ_DONE 0
# define HCI_REQ_PEND 1
# define HCI_REQ_CANCELED 2
2009-07-26 12:18:19 +04:00
# define hci_req_lock(d) mutex_lock(&d->req_lock)
# define hci_req_unlock(d) mutex_unlock(&d->req_lock)
2005-04-17 02:20:36 +04:00
void hci_req_complete ( struct hci_dev * hdev , int result ) ;
# endif /* __HCI_CORE_H */