Skip to content

Commit

Permalink
Bluetooth: Make HCI call directly into SCO and L2CAP event functions
Browse files Browse the repository at this point in the history
The struct hci_proto and all related register/unregister and dispatching
code was removed. HCI core code now call directly the SCO and L2CAP
event functions.

Signed-off-by: Ulisses Furquim <ulisses@profusion.mobi>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
  • Loading branch information
Ulisses Furquim authored and Gustavo F. Padovan committed Dec 22, 2011
1 parent 68a8aea commit 686ebf2
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 212 deletions.
138 changes: 59 additions & 79 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@
#include <linux/interrupt.h>
#include <net/bluetooth/hci.h>

/* HCI upper protocols */
#define HCI_PROTO_L2CAP 0
#define HCI_PROTO_SCO 1

/* HCI priority */
#define HCI_PRIO_MAX 7

Expand Down Expand Up @@ -330,12 +326,24 @@ struct hci_chan {
unsigned int sent;
};

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;

/* ----- HCI interface to upper protocols ----- */
extern int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
extern int l2cap_connect_cfm(struct hci_conn *hcon, u8 status);
extern int l2cap_disconn_ind(struct hci_conn *hcon);
extern int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason);
extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt);
extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags);

extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
extern int sco_connect_cfm(struct hci_conn *hcon, __u8 status);
extern int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason);
extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);

/* ----- Inquiry cache ----- */
#define INQUIRY_CACHE_AGE_MAX (HZ*30) /* 30 seconds */
#define INQUIRY_ENTRY_AGE_MAX (HZ*60) /* 60 seconds */
Expand Down Expand Up @@ -677,107 +685,87 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_host_le_capable(dev) ((dev)->extfeatures[0] & LMP_HOST_LE)

/* ----- HCI protocols ----- */
struct hci_proto {
char *name;
unsigned int id;
unsigned long flags;

void *priv;

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);
int (*disconn_cfm) (struct hci_conn *conn, __u8 reason);
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 (*security_cfm) (struct hci_conn *conn, __u8 status,
__u8 encrypt);
};

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);
switch (type) {
case ACL_LINK:
return l2cap_connect_ind(hdev, bdaddr);

hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->connect_ind)
mask |= hp->connect_ind(hdev, bdaddr, type);
case SCO_LINK:
case ESCO_LINK:
return sco_connect_ind(hdev, bdaddr);

return mask;
default:
BT_ERR("unknown link type %d", type);
return -EINVAL;
}
}

static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
{
register struct hci_proto *hp;
switch (conn->type) {
case ACL_LINK:
case LE_LINK:
l2cap_connect_cfm(conn, status);
break;

hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->connect_cfm)
hp->connect_cfm(conn, status);
case SCO_LINK:
case ESCO_LINK:
sco_connect_cfm(conn, status);
break;

hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->connect_cfm)
hp->connect_cfm(conn, status);
default:
BT_ERR("unknown link type %d", conn->type);
break;
}

if (conn->connect_cfm_cb)
conn->connect_cfm_cb(conn, status);
}

static inline int hci_proto_disconn_ind(struct hci_conn *conn)
{
register struct hci_proto *hp;
int reason = HCI_ERROR_REMOTE_USER_TERM;
if (conn->type != ACL_LINK && conn->type != LE_LINK)
return HCI_ERROR_REMOTE_USER_TERM;

hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->disconn_ind)
reason = hp->disconn_ind(conn);

hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->disconn_ind)
reason = hp->disconn_ind(conn);

return reason;
return l2cap_disconn_ind(conn);
}

static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
{
register struct hci_proto *hp;
switch (conn->type) {
case ACL_LINK:
case LE_LINK:
l2cap_disconn_cfm(conn, reason);
break;

hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->disconn_cfm)
hp->disconn_cfm(conn, reason);
case SCO_LINK:
case ESCO_LINK:
sco_disconn_cfm(conn, reason);
break;

hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->disconn_cfm)
hp->disconn_cfm(conn, reason);
default:
BT_ERR("unknown link type %d", conn->type);
break;
}

if (conn->disconn_cfm_cb)
conn->disconn_cfm_cb(conn, reason);
}

static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
{
register struct hci_proto *hp;
__u8 encrypt;

if (conn->type != ACL_LINK && conn->type != LE_LINK)
return;

if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
return;

encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;

hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->security_cfm)
hp->security_cfm(conn, status, encrypt);

hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->security_cfm)
hp->security_cfm(conn, status, encrypt);
l2cap_security_cfm(conn, status, encrypt);

if (conn->security_cfm_cb)
conn->security_cfm_cb(conn, status);
Expand All @@ -786,23 +774,15 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status,
__u8 encrypt)
{
register struct hci_proto *hp;

hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->security_cfm)
hp->security_cfm(conn, status, encrypt);
if (conn->type != ACL_LINK && conn->type != LE_LINK)
return;

hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->security_cfm)
hp->security_cfm(conn, status, encrypt);
l2cap_security_cfm(conn, status, encrypt);

if (conn->security_cfm_cb)
conn->security_cfm_cb(conn, status);
}

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;
Expand Down
59 changes: 4 additions & 55 deletions net/bluetooth/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,6 @@ DEFINE_RWLOCK(hci_dev_list_lock);
LIST_HEAD(hci_cb_list);
DEFINE_RWLOCK(hci_cb_list_lock);

/* HCI protocols */
#define HCI_MAX_PROTO 2
struct hci_proto *hci_proto[HCI_MAX_PROTO];

/* HCI notifiers list */
static ATOMIC_NOTIFIER_HEAD(hci_notifier);

Expand Down Expand Up @@ -1830,43 +1826,6 @@ EXPORT_SYMBOL(hci_recv_stream_fragment);

/* ---- Interface to upper protocols ---- */

/* Register/Unregister protocols. */
int hci_register_proto(struct hci_proto *hp)
{
int err = 0;

BT_DBG("%p name %s id %d", hp, hp->name, hp->id);

if (hp->id >= HCI_MAX_PROTO)
return -EINVAL;

if (!hci_proto[hp->id])
hci_proto[hp->id] = hp;
else
err = -EEXIST;

return err;
}
EXPORT_SYMBOL(hci_register_proto);

int hci_unregister_proto(struct hci_proto *hp)
{
int err = 0;

BT_DBG("%p name %s id %d", hp, hp->name, hp->id);

if (hp->id >= HCI_MAX_PROTO)
return -EINVAL;

if (hci_proto[hp->id])
hci_proto[hp->id] = NULL;
else
err = -ENOENT;

return err;
}
EXPORT_SYMBOL(hci_unregister_proto);

int hci_register_cb(struct hci_cb *cb)
{
BT_DBG("%p name %s", cb, cb->name);
Expand Down Expand Up @@ -2470,16 +2429,11 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_unlock(hdev);

if (conn) {
register struct hci_proto *hp;

hci_conn_enter_active_mode(conn, BT_POWER_FORCE_ACTIVE_OFF);

/* Send to upper protocol */
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->recv_acldata) {
hp->recv_acldata(conn, skb, flags);
return;
}
l2cap_recv_acldata(conn, skb, flags);
return;
} else {
BT_ERR("%s ACL packet for unknown connection handle %d",
hdev->name, handle);
Expand Down Expand Up @@ -2508,14 +2462,9 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_unlock(hdev);

if (conn) {
register struct hci_proto *hp;

/* Send to upper protocol */
hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->recv_scodata) {
hp->recv_scodata(conn, skb);
return;
}
sco_recv_scodata(conn, skb);
return;
} else {
BT_ERR("%s SCO packet for unknown connection handle %d",
hdev->name, handle);
Expand Down
Loading

0 comments on commit 686ebf2

Please sign in to comment.