2010-05-28 19:53:45 +04:00
/*
2005-04-17 02:20:36 +04:00
BlueZ - Bluetooth protocol stack for Linux
2010-05-28 19:53:46 +04:00
Copyright ( c ) 2000 - 2001 , 2010 , Code Aurora Forum . All rights reserved .
2005-04-17 02:20:36 +04:00
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
2010-05-28 19:53:45 +04:00
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
2005-04-17 02:20:36 +04:00
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
2010-05-28 19:53:45 +04:00
ALL LIABILITY , INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS ,
COPYRIGHTS , TRADEMARKS OR OTHER RIGHTS , RELATING TO USE OF THIS
2005-04-17 02:20:36 +04:00
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 {
2010-12-01 17:58:25 +03:00
struct inquiry_entry * next ;
2005-04-17 02:20:36 +04:00
__u32 timestamp ;
struct inquiry_data data ;
} ;
struct inquiry_cache {
2010-12-01 17:58:25 +03:00
spinlock_t lock ;
2005-04-17 02:20:36 +04:00
__u32 timestamp ;
2010-12-01 17:58:25 +03:00
struct inquiry_entry * list ;
2005-04-17 02:20:36 +04:00
} ;
struct hci_conn_hash {
struct list_head list ;
spinlock_t lock ;
unsigned int acl_num ;
unsigned int sco_num ;
2011-02-11 04:38:47 +03:00
unsigned int le_num ;
2005-04-17 02:20:36 +04:00
} ;
2010-05-18 15:20:32 +04:00
struct bdaddr_list {
struct list_head list ;
bdaddr_t bdaddr ;
} ;
2011-01-04 13:08:51 +03:00
struct bt_uuid {
struct list_head list ;
u8 uuid [ 16 ] ;
2011-01-13 22:56:52 +03:00
u8 svc_hint ;
2011-01-04 13:08:51 +03:00
} ;
2011-01-17 15:41:05 +03:00
struct link_key {
struct list_head list ;
bdaddr_t bdaddr ;
u8 type ;
u8 val [ 16 ] ;
u8 pin_len ;
} ;
2011-03-22 15:12:22 +03:00
struct oob_data {
struct list_head list ;
bdaddr_t bdaddr ;
u8 hash [ 16 ] ;
u8 randomizer [ 16 ] ;
} ;
2011-05-26 23:23:50 +04:00
struct adv_entry {
struct list_head list ;
bdaddr_t bdaddr ;
u8 bdaddr_type ;
} ;
2010-07-14 11:32:16 +04:00
# define NUM_REASSEMBLY 4
2005-04-17 02:20:36 +04:00
struct hci_dev {
struct list_head list ;
spinlock_t lock ;
atomic_t refcnt ;
char name [ 8 ] ;
unsigned long flags ;
__u16 id ;
2010-02-08 17:27:07 +03:00
__u8 bus ;
2010-02-13 04:28:41 +03:00
__u8 dev_type ;
2005-04-17 02:20:36 +04:00
bdaddr_t bdaddr ;
2011-03-16 15:29:35 +03:00
__u8 dev_name [ HCI_MAX_NAME_LENGTH ] ;
2011-03-28 15:07:23 +04:00
__u8 eir [ HCI_MAX_EIR_LENGTH ] ;
2007-10-20 15:33:56 +04:00
__u8 dev_class [ 3 ] ;
2011-01-13 22:56:52 +03:00
__u8 major_class ;
__u8 minor_class ;
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 ;
2011-01-25 02:19:58 +03:00
__u8 lmp_ver ;
2006-09-23 11:57:20 +04:00
__u16 manufacturer ;
2011-01-25 02:19:58 +03:00
__le16 lmp_subver ;
2005-04-17 02:20:36 +04:00
__u16 voice_setting ;
2011-01-25 14:28:33 +03:00
__u8 io_capability ;
2005-04-17 02:20:36 +04:00
__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 ;
2011-04-28 22:28:54 +04:00
unsigned int auto_accept_delay ;
2005-04-17 02:20:36 +04:00
unsigned long quirks ;
atomic_t cmd_cnt ;
unsigned int acl_cnt ;
unsigned int sco_cnt ;
2011-02-11 04:38:48 +03:00
unsigned int le_cnt ;
2005-04-17 02:20:36 +04:00
unsigned int acl_mtu ;
unsigned int sco_mtu ;
2011-02-11 04:38:48 +03:00
unsigned int le_mtu ;
2005-04-17 02:20:36 +04:00
unsigned int acl_pkts ;
unsigned int sco_pkts ;
2011-02-11 04:38:48 +03:00
unsigned int le_pkts ;
2005-04-17 02:20:36 +04:00
unsigned long acl_last_tx ;
unsigned long sco_last_tx ;
2011-02-11 04:38:48 +03:00
unsigned long le_last_tx ;
2005-04-17 02:20:36 +04:00
2010-03-20 17:20:04 +03:00
struct workqueue_struct * workqueue ;
2010-12-15 14:53:18 +03:00
struct work_struct power_on ;
struct work_struct power_off ;
struct timer_list off_timer ;
2011-02-16 17:32:41 +03:00
struct timer_list cmd_timer ;
2005-04-17 02:20:36 +04:00
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 ;
2010-07-14 11:32:16 +04:00
struct sk_buff * reassembly [ NUM_REASSEMBLY ] ;
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 ;
2011-01-10 14:28:59 +03:00
__u16 init_last_cmd ;
2005-04-17 02:20:36 +04:00
2011-06-10 01:50:43 +04:00
struct crypto_blkcipher * tfm ;
2005-04-17 02:20:36 +04:00
struct inquiry_cache inq_cache ;
struct hci_conn_hash conn_hash ;
2010-07-31 08:54:49 +04:00
struct list_head blacklist ;
2005-04-17 02:20:36 +04:00
2011-01-04 13:08:51 +03:00
struct list_head uuids ;
2011-01-17 15:41:05 +03:00
struct list_head link_keys ;
2011-03-22 15:12:22 +03:00
struct list_head remote_oob_data ;
2011-05-26 23:23:50 +04:00
struct list_head adv_entries ;
2011-05-26 23:23:53 +04:00
struct timer_list adv_timer ;
2011-05-26 23:23:50 +04:00
2005-04-17 02:20:36 +04:00
struct hci_dev_stats stat ;
struct sk_buff_head driver_init ;
void * driver_data ;
void * core_data ;
2010-12-01 17:58:25 +03:00
atomic_t promisc ;
2005-04-17 02:20:36 +04:00
2010-02-08 18:22:31 +03:00
struct dentry * debugfs ;
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 ;
2010-12-01 17:58:25 +03:00
struct module * owner ;
2005-04-17 02:20:36 +04:00
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 ;
2011-02-17 18:42:00 +03:00
atomic_t refcnt ;
spinlock_t lock ;
bdaddr_t dst ;
2011-06-07 13:18:06 +04:00
__u8 dst_type ;
2011-02-17 18:42:00 +03:00
__u16 handle ;
__u16 state ;
__u8 mode ;
__u8 type ;
__u8 out ;
__u8 attempt ;
__u8 dev_class [ 3 ] ;
__u8 features [ 8 ] ;
__u8 ssp_mode ;
__u16 interval ;
__u16 pkt_type ;
__u16 link_policy ;
__u32 link_mode ;
2011-04-28 14:07:55 +04:00
__u8 key_type ;
2011-02-17 18:42:00 +03:00
__u8 auth_type ;
__u8 sec_level ;
__u8 pending_sec_level ;
__u8 pin_length ;
__u8 io_capability ;
__u8 power_save ;
__u16 disc_timeout ;
unsigned long pend ;
2011-06-10 01:50:47 +04:00
__u8 ltk [ 16 ] ;
2006-07-03 12:02:33 +04:00
2011-01-04 16:40:05 +03:00
__u8 remote_cap ;
__u8 remote_oob ;
__u8 remote_auth ;
2011-02-17 18:42:00 +03: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 ;
2011-04-28 22:28:54 +04:00
struct timer_list auto_accept_timer ;
2006-07-03 12:02:33 +04:00
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 ;
2011-02-19 18:05:56 +03:00
void ( * connect_cfm_cb ) ( struct hci_conn * conn , u8 status ) ;
void ( * security_cfm_cb ) ( struct hci_conn * conn , u8 status ) ;
void ( * disconn_cfm_cb ) ( struct hci_conn * conn , u8 reason ) ;
2005-04-17 02:20:36 +04:00
} ;
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 ----- */
2010-12-01 17:58:25 +03:00
# define INQUIRY_CACHE_AGE_MAX (HZ*30) /* 30 seconds */
# define INQUIRY_ENTRY_AGE_MAX (HZ*60) /* 60 seconds */
2005-04-17 02:20:36 +04:00
# 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 ;
2010-09-23 00:43:57 +04:00
return c - > list = = NULL ;
2005-04-17 02:20:36 +04:00
}
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 ;
}
2011-06-07 13:18:06 +04:00
struct inquiry_entry * hci_inquiry_cache_lookup ( struct hci_dev * hdev ,
bdaddr_t * bdaddr ) ;
2005-04-17 02:20:36 +04:00
void hci_inquiry_cache_update ( struct hci_dev * hdev , struct inquiry_data * data ) ;
/* ----- HCI Connections ----- */
enum {
HCI_CONN_AUTH_PEND ,
2011-05-31 17:49:25 +04:00
HCI_CONN_REAUTH_PEND ,
2005-04-17 02:20:36 +04:00
HCI_CONN_ENCRYPT_PEND ,
2006-07-03 12:02:33 +04:00
HCI_CONN_RSWITCH_PEND ,
HCI_CONN_MODE_CHANGE_PEND ,
2010-07-26 18:06:00 +04:00
HCI_CONN_SCO_SETUP_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 ) ;
2011-02-11 04:38:47 +03:00
switch ( c - > type ) {
case ACL_LINK :
2005-04-17 02:20:36 +04:00
h - > acl_num + + ;
2011-02-11 04:38:47 +03:00
break ;
case LE_LINK :
h - > le_num + + ;
break ;
case SCO_LINK :
case ESCO_LINK :
2005-04-17 02:20:36 +04:00
h - > sco_num + + ;
2011-02-11 04:38:47 +03:00
break ;
}
2005-04-17 02:20:36 +04:00
}
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 ) ;
2011-02-11 04:38:47 +03:00
switch ( c - > type ) {
case ACL_LINK :
2005-04-17 02:20:36 +04:00
h - > acl_num - - ;
2011-02-11 04:38:47 +03:00
break ;
case LE_LINK :
h - > le_num - - ;
break ;
case SCO_LINK :
case ESCO_LINK :
2005-04-17 02:20:36 +04:00
h - > sco_num - - ;
2011-02-11 04:38:47 +03:00
break ;
}
2005-04-17 02:20:36 +04:00
}
static inline struct hci_conn * hci_conn_hash_lookup_handle ( struct hci_dev * hdev ,
2011-02-17 18:42:00 +03:00
__u16 handle )
2005-04-17 02:20:36 +04:00
{
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 ,
2011-02-17 18:42:00 +03:00
__u8 type , bdaddr_t * ba )
2005-04-17 02:20:36 +04:00
{
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 ,
2011-02-17 18:42:00 +03:00
__u8 type , __u16 state )
2006-10-15 19:30:56 +04:00
{
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 ) ;
2010-07-26 18:06:00 +04:00
void hci_sco_setup ( struct hci_conn * conn , __u8 status ) ;
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
2011-06-07 13:18:06 +04: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 ) ;
2011-05-06 11:42:31 +04:00
int hci_conn_check_secure ( struct hci_conn * conn , __u8 sec_level ) ;
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
2011-05-24 05:06:04 +04:00
void hci_conn_enter_active_mode ( struct hci_conn * conn , __u8 force_active ) ;
2006-07-03 12:02:33 +04:00
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 ;
2011-06-07 13:18:06 +04:00
} else {
2006-09-26 11:43:48 +04:00
timeo = msecs_to_jiffies ( 10 ) ;
2011-06-07 13:18:06 +04:00
}
} else {
2006-07-03 12:02:33 +04:00
timeo = msecs_to_jiffies ( 10 ) ;
2011-06-07 13:18:06 +04:00
}
2006-07-03 12:02:33 +04:00
mod_timer ( & conn - > disc_timer , jiffies + timeo ) ;
2005-04-17 02:20:36 +04:00
}
}
/* ----- 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 )
2010-05-28 19:53:45 +04:00
{
2005-04-17 02:20:36 +04:00
__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 ) ;
2010-05-18 15:20:32 +04:00
struct bdaddr_list * hci_blacklist_lookup ( struct hci_dev * hdev , bdaddr_t * bdaddr ) ;
int hci_blacklist_clear ( struct hci_dev * hdev ) ;
2011-01-04 13:08:51 +03:00
int hci_uuids_clear ( struct hci_dev * hdev ) ;
2011-01-17 15:41:05 +03:00
int hci_link_keys_clear ( struct hci_dev * hdev ) ;
struct link_key * hci_find_link_key ( struct hci_dev * hdev , bdaddr_t * bdaddr ) ;
2011-04-28 22:28:59 +04:00
int hci_add_link_key ( struct hci_dev * hdev , struct hci_conn * conn , int new_key ,
bdaddr_t * bdaddr , u8 * val , u8 type , u8 pin_len ) ;
2011-01-17 15:41:05 +03:00
int hci_remove_link_key ( struct hci_dev * hdev , bdaddr_t * bdaddr ) ;
2011-03-22 15:12:22 +03:00
int hci_remote_oob_data_clear ( struct hci_dev * hdev ) ;
struct oob_data * hci_find_remote_oob_data ( struct hci_dev * hdev ,
bdaddr_t * bdaddr ) ;
int hci_add_remote_oob_data ( struct hci_dev * hdev , bdaddr_t * bdaddr , u8 * hash ,
u8 * randomizer ) ;
int hci_remove_remote_oob_data ( struct hci_dev * hdev , bdaddr_t * bdaddr ) ;
2011-05-26 23:23:53 +04:00
# define ADV_CLEAR_TIMEOUT (3*60*HZ) /* Three minutes */
2011-05-26 23:23:50 +04:00
int hci_adv_entries_clear ( struct hci_dev * hdev ) ;
struct adv_entry * hci_find_adv_entry ( struct hci_dev * hdev , bdaddr_t * bdaddr ) ;
int hci_add_adv_entry ( struct hci_dev * hdev ,
struct hci_ev_le_advertising_info * ev ) ;
2010-12-15 14:53:18 +03:00
void hci_del_off_timer ( struct hci_dev * hdev ) ;
2005-04-17 02:20:36 +04:00
void hci_event_packet ( struct hci_dev * hdev , struct sk_buff * skb ) ;
2009-11-18 02:40:39 +03:00
int hci_recv_frame ( struct sk_buff * skb ) ;
2007-07-11 08:42:04 +04:00
int hci_recv_fragment ( struct hci_dev * hdev , int type , void * data , int count ) ;
2010-07-14 11:32:19 +04:00
int hci_recv_stream_fragment ( struct hci_dev * hdev , void * data , int count ) ;
2007-07-11 08:42:04 +04:00
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)
2011-01-03 12:14:36 +03:00
# define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH)
2011-02-11 04:38:48 +03:00
# define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE)
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 ;
2011-06-07 13:18:06 +04: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 ) ;
2011-06-07 13:18:06 +04:00
int ( * recv_acldata ) ( struct hci_conn * conn , struct sk_buff * skb ,
__u16 flags ) ;
2005-04-17 02:20:36 +04:00
int ( * recv_scodata ) ( struct hci_conn * conn , struct sk_buff * skb ) ;
2011-06-07 13:18:06 +04:00
int ( * security_cfm ) ( struct hci_conn * conn , __u8 status ,
__u8 encrypt ) ;
2005-04-17 02:20:36 +04:00
} ;
2011-06-07 13:18:06 +04:00
static inline int hci_proto_connect_ind ( struct hci_dev * hdev , bdaddr_t * bdaddr ,
__u8 type )
2005-04-17 02:20:36 +04:00
{
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 ) ;
2011-02-19 18:05:56 +03:00
if ( conn - > connect_cfm_cb )
conn - > connect_cfm_cb ( conn , status ) ;
2005-04-17 02:20:36 +04:00
}
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 ) ;
2011-02-19 18:05:56 +03:00
if ( conn - > disconn_cfm_cb )
conn - > disconn_cfm_cb ( 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 ) ;
2011-02-19 18:05:56 +03:00
if ( conn - > security_cfm_cb )
conn - > security_cfm_cb ( conn , status ) ;
2005-04-17 02:20:36 +04:00
}
2011-06-07 13:18:06 +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 ) ;
2011-02-19 18:05:56 +03:00
if ( conn - > security_cfm_cb )
conn - > security_cfm_cb ( conn , status ) ;
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 ;
2011-06-07 13:18:06 +04: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 ) ;
}
2011-06-07 13:18:06 +04:00
static inline void hci_encrypt_cfm ( struct hci_conn * conn , __u8 status ,
__u8 encrypt )
2005-04-17 02:20:36 +04:00
{
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 ) ;
}
2011-06-07 13:18:06 +04:00
static inline void hci_role_switch_cfm ( struct hci_conn * conn , __u8 status ,
__u8 role )
2005-04-17 02:20:36 +04:00
{
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 ) ;
2010-05-01 23:15:43 +04:00
void hci_send_acl ( struct hci_conn * conn , struct sk_buff * skb , __u16 flags ) ;
2010-05-01 23:15:35 +04:00
void hci_send_sco ( struct hci_conn * conn , struct sk_buff * skb ) ;
2005-04-17 02:20:36 +04:00
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 ----- */
2010-12-16 11:17:38 +03:00
void hci_send_to_sock ( struct hci_dev * hdev , struct sk_buff * skb ,
struct sock * skip_sk ) ;
2005-04-17 02:20:36 +04:00
2010-12-08 01:21:06 +03:00
/* Management interface */
int mgmt_control ( struct sock * sk , struct msghdr * msg , size_t len ) ;
2010-12-13 22:07:07 +03:00
int mgmt_index_added ( u16 index ) ;
int mgmt_index_removed ( u16 index ) ;
2010-12-16 11:00:37 +03:00
int mgmt_powered ( u16 index , u8 powered ) ;
2010-12-29 17:00:25 +03:00
int mgmt_discoverable ( u16 index , u8 discoverable ) ;
2010-12-30 01:18:33 +03:00
int mgmt_connectable ( u16 index , u8 connectable ) ;
2011-04-28 22:29:03 +04:00
int mgmt_new_key ( u16 index , struct link_key * key , u8 persistent ) ;
2011-01-20 13:34:39 +03:00
int mgmt_connected ( u16 index , bdaddr_t * bdaddr ) ;
int mgmt_disconnected ( u16 index , bdaddr_t * bdaddr ) ;
2011-01-20 13:40:27 +03:00
int mgmt_disconnect_failed ( u16 index ) ;
2011-01-22 07:09:08 +03:00
int mgmt_connect_failed ( u16 index , bdaddr_t * bdaddr , u8 status ) ;
2011-04-28 14:07:59 +04:00
int mgmt_pin_code_request ( u16 index , bdaddr_t * bdaddr , u8 secure ) ;
2011-01-22 07:10:07 +03:00
int mgmt_pin_code_reply_complete ( u16 index , bdaddr_t * bdaddr , u8 status ) ;
int mgmt_pin_code_neg_reply_complete ( u16 index , bdaddr_t * bdaddr , u8 status ) ;
2011-04-28 22:28:56 +04:00
int mgmt_user_confirm_request ( u16 index , bdaddr_t * bdaddr , __le32 value ,
u8 confirm_hint ) ;
2011-02-19 18:05:57 +03:00
int mgmt_user_confirm_reply_complete ( u16 index , bdaddr_t * bdaddr , u8 status ) ;
int mgmt_user_confirm_neg_reply_complete ( u16 index , bdaddr_t * bdaddr ,
u8 status ) ;
2011-02-19 18:06:00 +03:00
int mgmt_auth_failed ( u16 index , bdaddr_t * bdaddr , u8 status ) ;
2011-03-16 15:29:37 +03:00
int mgmt_set_local_name_complete ( u16 index , u8 * name , u8 status ) ;
2011-03-22 15:12:21 +03:00
int mgmt_read_local_oob_data_reply_complete ( u16 index , u8 * hash , u8 * randomizer ,
u8 status ) ;
2011-03-31 00:57:16 +04:00
int mgmt_device_found ( u16 index , bdaddr_t * bdaddr , u8 * dev_class , s8 rssi ,
u8 * eir ) ;
2011-03-30 14:18:12 +04:00
int mgmt_remote_name ( u16 index , bdaddr_t * bdaddr , u8 * name ) ;
2011-04-27 18:29:57 +04:00
int mgmt_discovering ( u16 index , u8 discovering ) ;
2010-12-08 01:21:06 +03:00
2005-04-17 02:20:36 +04:00
/* 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 ;
2010-12-08 01:21:05 +03:00
unsigned short channel ;
2005-04-17 02:20:36 +04:00
} ;
/* 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
2010-12-22 00:01:27 +03:00
void hci_req_complete ( struct hci_dev * hdev , __u16 cmd , int result ) ;
2005-04-17 02:20:36 +04:00
2011-02-17 01:44:53 +03:00
void hci_le_conn_update ( struct hci_conn * conn , u16 min , u16 max ,
u16 latency , u16 to_multiplier ) ;
2011-06-10 01:50:47 +04:00
void hci_le_start_enc ( struct hci_conn * conn , __le16 ediv , __u8 rand [ 8 ] ,
__u8 ltk [ 16 ] ) ;
void hci_le_ltk_reply ( struct hci_conn * conn , u8 ltk [ 16 ] ) ;
void hci_le_ltk_neg_reply ( struct hci_conn * conn ) ;
2005-04-17 02:20:36 +04:00
# endif /* __HCI_CORE_H */