--- zzzz-none-000/linux-2.4.17/include/net/bluetooth/hci_core.h 2001-09-07 16:28:38.000000000 +0000 +++ sangam-fb-401/linux-2.4.17/include/net/bluetooth/hci_core.h 2005-04-05 07:07:46.000000000 +0000 @@ -23,7 +23,7 @@ */ /* - * $Id: hci_core.h,v 1.11 2001/08/05 06:02:15 maxk Exp $ + * $Id: hci_core.h,v 1.5 2002/06/27 04:56:30 maxk Exp $ */ #ifndef __HCI_CORE_H @@ -32,14 +32,12 @@ #include /* HCI upper protocols */ -#define HCI_MAX_PROTO 1 #define HCI_PROTO_L2CAP 0 +#define HCI_PROTO_SCO 1 #define HCI_INIT_TIMEOUT (HZ * 10) -/* ----- Inquiry cache ----- */ -#define INQUIRY_CACHE_AGE_MAX (HZ*5) // 5 seconds -#define INQUIRY_ENTRY_AGE_MAX (HZ*60) // 60 seconds +/* HCI Core structures */ struct inquiry_entry { struct inquiry_entry *next; @@ -53,111 +51,188 @@ struct inquiry_entry *list; }; -static inline void inquiry_cache_init(struct inquiry_cache *cache) -{ - spin_lock_init(&cache->lock); - cache->list = NULL; -} +struct conn_hash { + struct list_head list; + spinlock_t lock; + unsigned int num; +}; -static inline void inquiry_cache_lock(struct inquiry_cache *cache) -{ - spin_lock(&cache->lock); -} +struct hci_dev { + struct list_head list; + spinlock_t lock; + atomic_t refcnt; -static inline void inquiry_cache_unlock(struct inquiry_cache *cache) -{ - spin_unlock(&cache->lock); -} + char name[8]; + unsigned long flags; + __u16 id; + __u8 type; + bdaddr_t bdaddr; + __u8 features[8]; -static inline void inquiry_cache_lock_bh(struct inquiry_cache *cache) -{ - spin_lock_bh(&cache->lock); -} + __u16 pkt_type; + __u16 link_policy; + __u16 link_mode; -static inline void inquiry_cache_unlock_bh(struct inquiry_cache *cache) -{ - spin_unlock_bh(&cache->lock); -} + unsigned long quirks; -static inline long inquiry_cache_age(struct inquiry_cache *cache) -{ - return jiffies - cache->timestamp; -} + atomic_t cmd_cnt; + unsigned int acl_cnt; + unsigned int sco_cnt; -static inline long inquiry_entry_age(struct inquiry_entry *e) -{ - return jiffies - e->timestamp; -} -extern void inquiry_cache_flush(struct inquiry_cache *cache); + unsigned int acl_mtu; + unsigned int sco_mtu; + unsigned int acl_pkts; + unsigned int sco_pkts; -struct hci_dev; + 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; + + struct semaphore req_lock; + wait_queue_head_t req_wait_q; + __u32 req_status; + __u32 req_result; + + struct inquiry_cache inq_cache; + struct conn_hash conn_hash; + + struct hci_dev_stats stat; + + void *driver_data; + void *core_data; + + atomic_t promisc; + + 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); + int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg); +}; -/* ----- HCI Connections ----- */ struct hci_conn { struct list_head list; + + atomic_t refcnt; + spinlock_t lock; + bdaddr_t dst; __u16 handle; + __u16 state; __u8 type; - unsigned int sent; + __u8 out; + __u32 link_mode; + unsigned long pend; + + unsigned int sent; + + struct sk_buff_head data_q; + struct timer_list timer; + struct hci_dev *hdev; void *l2cap_data; + void *sco_data; void *priv; - struct sk_buff_head data_q; + struct hci_conn *link; }; -struct conn_hash { - struct list_head list; - spinlock_t lock; - unsigned int num; -}; +extern struct hci_proto *hci_proto[]; +extern struct list_head hdev_list; +extern rwlock_t hdev_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 conn_hash_init(struct conn_hash *h) +static inline void inquiry_cache_init(struct hci_dev *hdev) { - INIT_LIST_HEAD(&h->list); - spin_lock_init(&h->lock); - h->num = 0; + struct inquiry_cache *c = &hdev->inq_cache; + spin_lock_init(&c->lock); + c->list = NULL; } -static inline void conn_hash_lock(struct conn_hash *h) +static inline int inquiry_cache_empty(struct hci_dev *hdev) { - spin_lock(&h->lock); + struct inquiry_cache *c = &hdev->inq_cache; + return (c->list == NULL); } -static inline void conn_hash_unlock(struct conn_hash *h) +static inline long inquiry_cache_age(struct hci_dev *hdev) { - spin_unlock(&h->lock); + struct inquiry_cache *c = &hdev->inq_cache; + return jiffies - c->timestamp; } -static inline void __conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c) +static inline long inquiry_entry_age(struct inquiry_entry *e) { - list_add(&c->list, &h->list); - h->num++; + return jiffies - e->timestamp; } -static inline void conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c) +struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); +void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info); +void inquiry_cache_flush(struct hci_dev *hdev); +int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf); + +/* ----- HCI Connections ----- */ +enum { + HCI_CONN_AUTH_PEND, + HCI_CONN_ENCRYPT_PEND +}; + +#define hci_conn_lock(c) spin_lock(&c->lock) +#define hci_conn_unlock(c) spin_unlock(&c->lock) +#define hci_conn_lock_bh(c) spin_lock_bh(&c->lock) +#define hci_conn_unlock_bh(c) spin_unlock_bh(&c->lock) + +#define conn_hash_lock(d) spin_lock(&d->conn_hash->lock) +#define conn_hash_unlock(d) spin_unlock(&d->conn_hash->lock) +#define conn_hash_lock_bh(d) spin_lock_bh(&d->conn_hash->lock) +#define conn_hash_unlock_bh(d) spin_unlock_bh(&d->conn_hash->lock) + +static inline void conn_hash_init(struct hci_dev *hdev) { - conn_hash_lock(h); - __conn_hash_add(h, handle, c); - conn_hash_unlock(h); + struct conn_hash *h = &hdev->conn_hash; + INIT_LIST_HEAD(&h->list); + spin_lock_init(&h->lock); + h->num = 0; } -static inline void __conn_hash_del(struct conn_hash *h, struct hci_conn *c) +static inline void conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) { - list_del(&c->list); - h->num--; + struct conn_hash *h = &hdev->conn_hash; + list_add(&c->list, &h->list); + h->num++; } -static inline void conn_hash_del(struct conn_hash *h, struct hci_conn *c) +static inline void conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) { - conn_hash_lock(h); - __conn_hash_del(h, c); - conn_hash_unlock(h); + struct conn_hash *h = &hdev->conn_hash; + list_del(&c->list); + h->num--; } -static inline struct hci_conn *__conn_hash_lookup(struct conn_hash *h, __u16 handle) +static inline struct hci_conn *conn_hash_lookup_handle(struct hci_dev *hdev, + __u16 handle) { + register struct conn_hash *h = &hdev->conn_hash; register struct list_head *p; register struct hci_conn *c; @@ -169,101 +244,97 @@ return NULL; } -static inline struct hci_conn *conn_hash_lookup(struct conn_hash *h, __u16 handle) +static inline struct hci_conn *conn_hash_lookup_ba(struct hci_dev *hdev, + __u8 type, bdaddr_t *ba) { - struct hci_conn *conn; + register struct conn_hash *h = &hdev->conn_hash; + register struct list_head *p; + register struct hci_conn *c; - conn_hash_lock(h); - conn = __conn_hash_lookup(h, handle); - conn_hash_unlock(h); - return conn; + 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; } -/* ----- HCI Devices ----- */ -struct hci_dev { - atomic_t refcnt; - - char name[8]; - __u32 flags; - __u16 id; - __u8 type; - bdaddr_t bdaddr; - __u8 features[8]; - - __u16 pkt_type; - - atomic_t cmd_cnt; - unsigned int acl_cnt; - unsigned int sco_cnt; - - unsigned int acl_mtu; - unsigned int sco_mtu; - unsigned int acl_max; - unsigned int sco_max; - - void *driver_data; - void *l2cap_data; - void *priv; - - 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; +void hci_acl_connect(struct hci_conn *conn); +void hci_acl_disconn(struct hci_conn *conn, __u8 reason); +void hci_add_sco(struct hci_conn *conn, __u16 handle); - struct semaphore req_lock; - wait_queue_head_t req_wait_q; - __u32 req_status; - __u32 req_result; +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); +int hci_conn_del(struct hci_conn *conn); +void hci_conn_hash_flush(struct hci_dev *hdev); - struct inquiry_cache inq_cache; +struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src); +int hci_conn_auth(struct hci_conn *conn); +int hci_conn_encrypt(struct hci_conn *conn); - struct conn_hash conn_hash; - - struct hci_dev_stats stat; - - int (*open)(struct hci_dev *hdev); - int (*close)(struct hci_dev *hdev); - int (*flush)(struct hci_dev *hdev); - int (*send)(struct sk_buff *skb); -}; +static inline void hci_conn_set_timer(struct hci_conn *conn, long timeout) +{ + mod_timer(&conn->timer, jiffies + timeout); +} -static inline void hci_dev_hold(struct hci_dev *hdev) +static inline void hci_conn_del_timer(struct hci_conn *conn) { - atomic_inc(&hdev->refcnt); + del_timer(&conn->timer); } -static inline void hci_dev_put(struct hci_dev *hdev) +static inline void hci_conn_hold(struct hci_conn *conn) { - atomic_dec(&hdev->refcnt); + atomic_inc(&conn->refcnt); + hci_conn_del_timer(conn); } -extern struct hci_dev *hci_dev_get(int index); -extern int hci_register_dev(struct hci_dev *hdev); -extern int hci_unregister_dev(struct hci_dev *hdev); -extern int hci_dev_open(__u16 dev); -extern int hci_dev_close(__u16 dev); -extern int hci_dev_reset(__u16 dev); -extern int hci_dev_reset_stat(__u16 dev); -extern int hci_dev_info(unsigned long arg); -extern int hci_dev_list(unsigned long arg); -extern int hci_dev_setscan(unsigned long arg); -extern int hci_dev_setauth(unsigned long arg); -extern int hci_dev_setptype(unsigned long arg); -extern int hci_conn_list(unsigned long arg); -extern int hci_inquiry(unsigned long arg); +static inline void hci_conn_put(struct hci_conn *conn) +{ + if (atomic_dec_and_test(&conn->refcnt)) { + if (conn->type == ACL_LINK) { + unsigned long timeo = (conn->out) ? + HCI_DISCONN_TIMEOUT : HCI_DISCONN_TIMEOUT * 2; + hci_conn_set_timer(conn, timeo); + } else + hci_conn_set_timer(conn, HZ / 100); + } +} -extern __u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode); -extern __u32 hci_dev_getmode(struct hci_dev *hdev); +/* ----- HCI Devices ----- */ +static inline void hci_dev_put(struct hci_dev *d) +{ + if (atomic_dec_and_test(&d->refcnt)) + d->destruct(d); +} +#define hci_dev_hold(d) atomic_inc(&d->refcnt) + +#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); +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, unsigned long arg); +int hci_get_dev_list(unsigned long arg); +int hci_get_dev_info(unsigned long arg); +int hci_get_conn_list(unsigned long arg); +int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg); +int hci_inquiry(unsigned long arg); -extern int hci_recv_frame(struct sk_buff *skb); +int hci_recv_frame(struct sk_buff *skb); +void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); /* ----- LMP capabilities ----- */ #define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH) +#define lmp_encrypt_capable(dev) (dev->features[0] & LMP_ENCRYPT) /* ----- HCI tasks ----- */ static inline void hci_sched_cmd(struct hci_dev *hdev) @@ -284,43 +355,130 @@ /* ----- HCI protocols ----- */ struct hci_proto { char *name; - __u32 id; - __u32 flags; + unsigned int id; + unsigned long flags; void *priv; - int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr); - int (*connect_cfm) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *conn); + int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type); + int (*connect_cfm) (struct hci_conn *conn, __u8 status); int (*disconn_ind) (struct hci_conn *conn, __u8 reason); - int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb , __u16 flags); + int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags); int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb); + int (*auth_cfm) (struct hci_conn *conn, __u8 status); + int (*encrypt_cfm) (struct hci_conn *conn, __u8 status); }; -extern int hci_register_proto(struct hci_proto *hproto); -extern int hci_unregister_proto(struct hci_proto *hproto); -extern int hci_register_notifier(struct notifier_block *nb); -extern int hci_unregister_notifier(struct notifier_block *nb); -extern int hci_connect(struct hci_dev * hdev, bdaddr_t * bdaddr); -extern int hci_disconnect(struct hci_conn *conn, __u8 reason); -extern int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void * param); -extern int hci_send_raw(struct sk_buff *skb); -extern int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags); -extern int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); +static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) +{ + register struct hci_proto *hp; + int mask = 0; + + 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); +} + +static inline void hci_proto_disconn_ind(struct hci_conn *conn, __u8 reason) +{ + register struct hci_proto *hp; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->disconn_ind) + hp->disconn_ind(conn, reason); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->disconn_ind) + hp->disconn_ind(conn, reason); +} + +static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) +{ + register struct hci_proto *hp; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->auth_cfm) + hp->auth_cfm(conn, status); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->auth_cfm) + hp->auth_cfm(conn, status); +} + +static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status) +{ + register struct hci_proto *hp; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->encrypt_cfm) + hp->encrypt_cfm(conn, status); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->encrypt_cfm) + hp->encrypt_cfm(conn, status); +} + +int hci_register_proto(struct hci_proto *hproto); +int hci_unregister_proto(struct hci_proto *hproto); +int hci_register_notifier(struct notifier_block *nb); +int hci_unregister_notifier(struct notifier_block *nb); + +int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param); +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); + +void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf); + +void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); /* ----- HCI Sockets ----- */ -extern void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); +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->protinfo) +#define hci_pi(sk) ((struct hci_pinfo *) &sk->tp_pinfo) struct hci_pinfo { 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 +#define hci_req_lock(d) down(&d->req_lock) +#define hci_req_unlock(d) up(&d->req_lock) + +void hci_req_complete(struct hci_dev *hdev, int result); +void hci_req_cancel(struct hci_dev *hdev, int err); + #endif /* __HCI_CORE_H */