Commit 791ef39c authored by John W. Linville's avatar John W. Linville
Browse files
parents e5a87625 0c1abbd1
......@@ -681,7 +681,7 @@ static int bluecard_hci_send_frame(struct sk_buff *skb)
case HCI_SCODATA_PKT:
hdev->stat.sco_tx++;
break;
};
}
/* Prepend skb with frame type */
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
......
......@@ -600,8 +600,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
exit:
if (ret) {
hdev->stat.err_rx++;
if (skb)
kfree_skb(skb);
kfree_skb(skb);
}
return ret;
......
......@@ -446,7 +446,7 @@ static int btuart_hci_send_frame(struct sk_buff *skb)
case HCI_SCODATA_PKT:
hdev->stat.sco_tx++;
break;
};
}
/* Prepend skb with frame type */
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
......
......@@ -96,11 +96,12 @@ static struct usb_device_id btusb_table[] = {
{ USB_DEVICE(0x0c10, 0x0000) },
/* Broadcom BCM20702A0 */
{ USB_DEVICE(0x04ca, 0x2003) },
{ USB_DEVICE(0x0489, 0xe042) },
{ USB_DEVICE(0x413c, 0x8197) },
/* Foxconn - Hon Hai */
{ USB_DEVICE(0x0489, 0xe033) },
{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
/*Broadcom devices with vendor specific id */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
......
......@@ -358,21 +358,7 @@ static struct platform_driver btwilink_driver = {
},
};
/* ------- Module Init/Exit interfaces ------ */
static int __init btwilink_init(void)
{
BT_INFO("Bluetooth Driver for TI WiLink - Version %s", VERSION);
return platform_driver_register(&btwilink_driver);
}
static void __exit btwilink_exit(void)
{
platform_driver_unregister(&btwilink_driver);
}
module_init(btwilink_init);
module_exit(btwilink_exit);
module_platform_driver(btwilink_driver);
/* ------ Module Info ------ */
......
......@@ -531,7 +531,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
default:
err = n_tty_ioctl_helper(tty, file, cmd, arg);
break;
};
}
return err;
}
......
......@@ -481,7 +481,7 @@ static int ll_recv(struct hci_uart *hu, void *data, int count)
hu->hdev->stat.err_rx++;
ptr++; count--;
continue;
};
}
ptr++; count--;
......
......@@ -156,7 +156,7 @@ static inline ssize_t vhci_put_user(struct vhci_data *data,
case HCI_SCODATA_PKT:
data->hdev->stat.sco_tx++;
break;
};
}
return total;
}
......
......@@ -302,8 +302,11 @@ enum {
/* ---- HCI Error Codes ---- */
#define HCI_ERROR_AUTH_FAILURE 0x05
#define HCI_ERROR_CONNECTION_TIMEOUT 0x08
#define HCI_ERROR_REJ_BAD_ADDR 0x0f
#define HCI_ERROR_REMOTE_USER_TERM 0x13
#define HCI_ERROR_REMOTE_LOW_RESOURCES 0x14
#define HCI_ERROR_REMOTE_POWER_OFF 0x15
#define HCI_ERROR_LOCAL_HOST_TERM 0x16
#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18
......@@ -1246,6 +1249,24 @@ struct hci_ev_simple_pair_complete {
bdaddr_t bdaddr;
} __packed;
#define HCI_EV_USER_PASSKEY_NOTIFY 0x3b
struct hci_ev_user_passkey_notify {
bdaddr_t bdaddr;
__le32 passkey;
} __packed;
#define HCI_KEYPRESS_STARTED 0
#define HCI_KEYPRESS_ENTERED 1
#define HCI_KEYPRESS_ERASED 2
#define HCI_KEYPRESS_CLEARED 3
#define HCI_KEYPRESS_COMPLETED 4
#define HCI_EV_KEYPRESS_NOTIFY 0x3c
struct hci_ev_keypress_notify {
bdaddr_t bdaddr;
__u8 type;
} __packed;
#define HCI_EV_REMOTE_HOST_FEATURES 0x3d
struct hci_ev_remote_host_features {
bdaddr_t bdaddr;
......
......@@ -303,6 +303,8 @@ struct hci_conn {
__u8 pin_length;
__u8 enc_key_size;
__u8 io_capability;
__u32 passkey_notify;
__u8 passkey_entered;
__u16 disc_timeout;
unsigned long flags;
......@@ -428,15 +430,6 @@ static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
test_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
}
static inline void hci_conn_hash_init(struct hci_dev *hdev)
{
struct hci_conn_hash *h = &hdev->conn_hash;
INIT_LIST_HEAD(&h->list);
h->acl_num = 0;
h->sco_num = 0;
h->le_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;
......@@ -551,9 +544,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
return NULL;
}
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);
void hci_setup_sync(struct hci_conn *conn, __u16 handle);
void hci_sco_setup(struct hci_conn *conn, __u8 status);
......@@ -563,7 +554,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev);
void hci_conn_check_pending(struct hci_dev *hdev);
struct hci_chan *hci_chan_create(struct hci_conn *conn);
int hci_chan_del(struct hci_chan *chan);
void hci_chan_del(struct hci_chan *chan);
void hci_chan_list_flush(struct hci_conn *conn);
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
......@@ -614,11 +605,17 @@ static inline void hci_conn_put(struct hci_conn *conn)
/* ----- HCI Devices ----- */
static inline void hci_dev_put(struct hci_dev *d)
{
BT_DBG("%s orig refcnt %d", d->name,
atomic_read(&d->dev.kobj.kref.refcount));
put_device(&d->dev);
}
static inline struct hci_dev *hci_dev_hold(struct hci_dev *d)
{
BT_DBG("%s orig refcnt %d", d->name,
atomic_read(&d->dev.kobj.kref.refcount));
get_device(&d->dev);
return d;
}
......@@ -1004,7 +1001,7 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u32 flags, u8 *name, u8 name_len,
u8 *dev_class);
int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type);
u8 link_type, u8 addr_type, u8 reason);
int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u8 status);
int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
......@@ -1027,6 +1024,9 @@ int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u8 status);
int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u8 status);
int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u32 passkey,
u8 entered);
int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 status);
int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
......
......@@ -433,11 +433,10 @@ struct l2cap_chan {
struct sock *sk;
struct l2cap_conn *conn;
struct kref kref;
__u8 state;
atomic_t refcnt;
__le16 psm;
__u16 dcid;
__u16 scid;
......
......@@ -405,7 +405,16 @@ struct mgmt_ev_device_connected {
__u8 eir[0];
} __packed;
#define MGMT_DEV_DISCONN_UNKNOWN 0x00
#define MGMT_DEV_DISCONN_TIMEOUT 0x01
#define MGMT_DEV_DISCONN_LOCAL_HOST 0x02
#define MGMT_DEV_DISCONN_REMOTE 0x03
#define MGMT_EV_DEVICE_DISCONNECTED 0x000C
struct mgmt_ev_device_disconnected {
struct mgmt_addr_info addr;
__u8 reason;
} __packed;
#define MGMT_EV_CONNECT_FAILED 0x000D
struct mgmt_ev_connect_failed {
......@@ -469,3 +478,10 @@ struct mgmt_ev_device_unblocked {
struct mgmt_ev_device_unpaired {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_EV_PASSKEY_NOTIFY 0x0017
struct mgmt_ev_passkey_notify {
struct mgmt_addr_info addr;
__le32 passkey;
__u8 entered;
} __packed;
......@@ -567,8 +567,6 @@ static void bt_seq_stop(struct seq_file *seq, void *v)
static int bt_seq_show(struct seq_file *seq, void *v)
{
struct sock *sk;
struct bt_sock *bt;
struct bt_seq_state *s = seq->private;
struct bt_sock_list *l = s->l;
bdaddr_t src_baswapped, dst_baswapped;
......@@ -583,8 +581,8 @@ static int bt_seq_show(struct seq_file *seq, void *v)
seq_putc(seq, '\n');
} else {
sk = sk_entry(v);
bt = bt_sk(sk);
struct sock *sk = sk_entry(v);
struct bt_sock *bt = bt_sk(sk);
baswap(&src_baswapped, &bt->src);
baswap(&dst_baswapped, &bt->dst);
......@@ -624,7 +622,7 @@ static int bt_seq_open(struct inode *inode, struct file *file)
sk_list = PDE(inode)->data;
s = __seq_open_private(file, &bt_seq_ops,
sizeof(struct bt_seq_state));
if (s == NULL)
if (!s)
return -ENOMEM;
s->l = sk_list;
......@@ -646,7 +644,7 @@ int bt_procfs_init(struct module* module, struct net *net, const char *name,
sk_list->fops.release = seq_release_private;
pde = proc_net_fops_create(net, name, 0, &sk_list->fops);
if (pde == NULL)
if (!pde)
return -ENOMEM;
pde->data = sk_list;
......
......@@ -31,7 +31,7 @@
#include <net/bluetooth/a2mp.h>
#include <net/bluetooth/smp.h>
static void hci_le_connect(struct hci_conn *conn)
static void hci_le_create_connection(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_create_conn cp;
......@@ -55,12 +55,12 @@ static void hci_le_connect(struct hci_conn *conn)
hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
}
static void hci_le_connect_cancel(struct hci_conn *conn)
static void hci_le_create_connection_cancel(struct hci_conn *conn)
{
hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
}
void hci_acl_connect(struct hci_conn *conn)
static void hci_acl_create_connection(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
struct inquiry_entry *ie;
......@@ -104,7 +104,7 @@ void hci_acl_connect(struct hci_conn *conn)
hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
}
static void hci_acl_connect_cancel(struct hci_conn *conn)
static void hci_acl_create_connection_cancel(struct hci_conn *conn)
{
struct hci_cp_create_conn_cancel cp;
......@@ -130,7 +130,7 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
}
void hci_add_sco(struct hci_conn *conn, __u16 handle)
static void hci_add_sco(struct hci_conn *conn, __u16 handle)
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_add_sco cp;
......@@ -246,9 +246,9 @@ static void hci_conn_timeout(struct work_struct *work)
case BT_CONNECT2:
if (conn->out) {
if (conn->type == ACL_LINK)
hci_acl_connect_cancel(conn);
hci_acl_create_connection_cancel(conn);
else if (conn->type == LE_LINK)
hci_le_connect_cancel(conn);
hci_le_create_connection_cancel(conn);
}
break;
case BT_CONFIG:
......@@ -471,40 +471,37 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
}
EXPORT_SYMBOL(hci_get_route);
/* Create SCO, ACL or LE connection.
* Device _must_ be locked */
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
__u8 dst_type, __u8 sec_level, __u8 auth_type)
static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, u8 sec_level, u8 auth_type)
{
struct hci_conn *acl;
struct hci_conn *sco;
struct hci_conn *le;
BT_DBG("%s dst %s", hdev->name, batostr(dst));
le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
if (!le) {
le = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
if (le)
return ERR_PTR(-EBUSY);
if (type == LE_LINK) {
le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
if (!le) {
le = hci_conn_hash_lookup_state(hdev, LE_LINK,
BT_CONNECT);
if (le)
return ERR_PTR(-EBUSY);
le = hci_conn_add(hdev, LE_LINK, dst);
if (!le)
return ERR_PTR(-ENOMEM);
le = hci_conn_add(hdev, LE_LINK, dst);
if (!le)
return ERR_PTR(-ENOMEM);
le->dst_type = bdaddr_to_le(dst_type);
hci_le_create_connection(le);
}
le->dst_type = bdaddr_to_le(dst_type);
hci_le_connect(le);
}
le->pending_sec_level = sec_level;
le->auth_type = auth_type;
le->pending_sec_level = sec_level;
le->auth_type = auth_type;
hci_conn_hold(le);
hci_conn_hold(le);
return le;
}
return le;
}
static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
u8 sec_level, u8 auth_type)
{
struct hci_conn *acl;
acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
if (!acl) {
......@@ -519,10 +516,20 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
acl->sec_level = BT_SECURITY_LOW;
acl->pending_sec_level = sec_level;
acl->auth_type = auth_type;
hci_acl_connect(acl);
hci_acl_create_connection(acl);
}
if (type == ACL_LINK)
return acl;
}
static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type,
bdaddr_t *dst, u8 sec_level, u8 auth_type)
{
struct hci_conn *acl;
struct hci_conn *sco;
acl = hci_connect_acl(hdev, dst, sec_level, auth_type);
if (IS_ERR(acl))
return acl;
sco = hci_conn_hash_lookup_ba(hdev, type, dst);
......@@ -556,6 +563,25 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
return sco;
}
/* Create SCO, ACL or LE connection. */
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
__u8 dst_type, __u8 sec_level, __u8 auth_type)
{
BT_DBG("%s dst %s type 0x%x", hdev->name, batostr(dst), type);
switch (type) {
case LE_LINK:
return hci_connect_le(hdev, dst, dst_type, sec_level, auth_type);
case ACL_LINK:
return hci_connect_acl(hdev, dst, sec_level, auth_type);
case SCO_LINK:
case ESCO_LINK:
return hci_connect_sco(hdev, type, dst, sec_level, auth_type);
}
return ERR_PTR(-EINVAL);
}
/* Check link security requirement */
int hci_conn_check_link_mode(struct hci_conn *conn)
{
......@@ -775,7 +801,7 @@ void hci_conn_check_pending(struct hci_dev *hdev)
conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
if (conn)
hci_acl_connect(conn);
hci_acl_create_connection(conn);
hci_dev_unlock(hdev);
}
......@@ -913,7 +939,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn)
return chan;
}
int hci_chan_del(struct hci_chan *chan)
void hci_chan_del(struct hci_chan *chan)
{
struct hci_conn *conn = chan->conn;
struct hci_dev *hdev = conn->hdev;
......@@ -926,8 +952,6 @@ int hci_chan_del(struct hci_chan *chan)
skb_queue_purge(&chan->data_q);
kfree(chan);
return 0;
}
void hci_chan_list_flush(struct hci_conn *conn)
......
......@@ -231,6 +231,9 @@ static void amp_init(struct hci_dev *hdev)
/* Read Local AMP Info */
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
/* Read Data Blk size */
hci_send_cmd(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, 0, NULL);
}
static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
......@@ -268,7 +271,6 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
BT_ERR("Unknown device type %d", hdev->dev_type);
break;
}
}
static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt)
......@@ -1652,6 +1654,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_LIST_HEAD(&hdev->link_keys);
INIT_LIST_HEAD(&hdev->long_term_keys);
INIT_LIST_HEAD(&hdev->remote_oob_data);
INIT_LIST_HEAD(&hdev->conn_hash.list);
INIT_WORK(&hdev->rx_work, hci_rx_work);
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
......@@ -1674,7 +1677,6 @@ struct hci_dev *hci_alloc_dev(void)
hci_init_sysfs(hdev);
discovery_init(hdev);
hci_conn_hash_init(hdev);
return hdev;
}
......
......@@ -29,6 +29,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/mgmt.h>
/* Handle HCI Event packets */
......@@ -303,7 +304,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_lock(hdev);
if (status != 0) {
if (status) {
mgmt_write_scan_failed(hdev, param, status);
hdev->discov_timeout = 0;
goto done;
......@@ -925,7 +926,7 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
if (test_bit(HCI_MGMT, &hdev->dev_flags))
mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);
if (rp->status != 0)
if (rp->status)
goto unlock;
cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
......@@ -1891,6 +1892,22 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
}
}
static u8 hci_to_mgmt_reason(u8 err)
{
switch (err) {
case HCI_ERROR_CONNECTION_TIMEOUT:
return MGMT_DEV_DISCONN_TIMEOUT;
case HCI_ERROR_REMOTE_USER_TERM:
case HCI_ERROR_REMOTE_LOW_RESOURCES:
case HCI_ERROR_REMOTE_POWER_OFF:
return MGMT_DEV_DISCONN_REMOTE;
case HCI_ERROR_LOCAL_HOST_TERM:
return MGMT_DEV_DISCONN_LOCAL_HOST;
default:
return MGMT_DEV_DISCONN_UNKNOWN;
}
}
static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_disconn_complete *ev = (void *) skb->data;
......@@ -1909,12 +1926,15 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
(conn->type == ACL_LINK || conn->type == LE_LINK)) {
if (ev->status != 0)
if (ev->status) {
mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, ev->status);
else
} else {
u8 reason = hci_to_mgmt_reason(ev->reason);
mgmt_device_disconnected(hdev, &conn->dst, conn->type,
conn->dst_type);
conn->dst_type, reason);
}
}
if (ev->status == 0) {
......@@ -3259,6 +3279,65 @@ static void hci_user_passkey_request_evt(struct hci_dev *hdev,
mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0);
}
static void hci_user_passkey_notify_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_ev_user_passkey_notify *ev = (void *) skb->data;
struct hci_conn *conn;
BT_DBG("%s", hdev->name);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (!conn)
return;
conn->passkey_notify = __le32_to_cpu(ev->passkey);
conn->passkey_entered = 0;
if (test_bit(HCI_MGMT, &hdev->dev_flags))
mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
conn->dst_type, conn->passkey_notify,
conn->passkey_entered);
}
static void hci_keypress_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_keypress_notify *ev = (void *) skb->data;
struct hci_conn *conn;
BT_DBG("%s", hdev->name);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (!conn)
return;
switch (ev->type) {
case HCI_KEYPRESS_STARTED:
conn->passkey_entered = 0;
return;
case HCI_KEYPRESS_ENTERED: