Commit 407d819c authored by David S. Miller's avatar David S. Miller
parents 7abbcd6a b1235d79
...@@ -2346,6 +2346,7 @@ COMPATIBLE_IOCTL(HCIGETDEVLIST) ...@@ -2346,6 +2346,7 @@ COMPATIBLE_IOCTL(HCIGETDEVLIST)
COMPATIBLE_IOCTL(HCIGETDEVINFO) COMPATIBLE_IOCTL(HCIGETDEVINFO)
COMPATIBLE_IOCTL(HCIGETCONNLIST) COMPATIBLE_IOCTL(HCIGETCONNLIST)
COMPATIBLE_IOCTL(HCIGETCONNINFO) COMPATIBLE_IOCTL(HCIGETCONNINFO)
COMPATIBLE_IOCTL(HCIGETAUTHINFO)
COMPATIBLE_IOCTL(HCISETRAW) COMPATIBLE_IOCTL(HCISETRAW)
COMPATIBLE_IOCTL(HCISETSCAN) COMPATIBLE_IOCTL(HCISETSCAN)
COMPATIBLE_IOCTL(HCISETAUTH) COMPATIBLE_IOCTL(HCISETAUTH)
......
...@@ -121,6 +121,7 @@ void bt_sock_link(struct bt_sock_list *l, struct sock *s); ...@@ -121,6 +121,7 @@ void bt_sock_link(struct bt_sock_list *l, struct sock *s);
void bt_sock_unlink(struct bt_sock_list *l, struct sock *s); void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags); int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags);
uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait); uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo); int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
void bt_accept_enqueue(struct sock *parent, struct sock *sk); void bt_accept_enqueue(struct sock *parent, struct sock *sk);
......
...@@ -72,8 +72,6 @@ enum { ...@@ -72,8 +72,6 @@ enum {
HCI_INQUIRY, HCI_INQUIRY,
HCI_RAW, HCI_RAW,
HCI_SECMGR
}; };
/* HCI ioctl defines */ /* HCI ioctl defines */
...@@ -86,6 +84,7 @@ enum { ...@@ -86,6 +84,7 @@ enum {
#define HCIGETDEVINFO _IOR('H', 211, int) #define HCIGETDEVINFO _IOR('H', 211, int)
#define HCIGETCONNLIST _IOR('H', 212, int) #define HCIGETCONNLIST _IOR('H', 212, int)
#define HCIGETCONNINFO _IOR('H', 213, int) #define HCIGETCONNINFO _IOR('H', 213, int)
#define HCIGETAUTHINFO _IOR('H', 215, int)
#define HCISETRAW _IOW('H', 220, int) #define HCISETRAW _IOW('H', 220, int)
#define HCISETSCAN _IOW('H', 221, int) #define HCISETSCAN _IOW('H', 221, int)
...@@ -97,8 +96,6 @@ enum { ...@@ -97,8 +96,6 @@ enum {
#define HCISETACLMTU _IOW('H', 227, int) #define HCISETACLMTU _IOW('H', 227, int)
#define HCISETSCOMTU _IOW('H', 228, int) #define HCISETSCOMTU _IOW('H', 228, int)
#define HCISETSECMGR _IOW('H', 230, int)
#define HCIINQUIRY _IOR('H', 240, int) #define HCIINQUIRY _IOR('H', 240, int)
/* HCI timeouts */ /* HCI timeouts */
...@@ -137,6 +134,8 @@ enum { ...@@ -137,6 +134,8 @@ enum {
#define ESCO_EV4 0x0010 #define ESCO_EV4 0x0010
#define ESCO_EV5 0x0020 #define ESCO_EV5 0x0020
#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3)
/* ACL flags */ /* ACL flags */
#define ACL_CONT 0x01 #define ACL_CONT 0x01
#define ACL_START 0x02 #define ACL_START 0x02
...@@ -178,6 +177,8 @@ enum { ...@@ -178,6 +177,8 @@ enum {
#define LMP_SNIFF_SUBR 0x02 #define LMP_SNIFF_SUBR 0x02
#define LMP_SIMPLE_PAIR 0x08
/* Connection modes */ /* Connection modes */
#define HCI_CM_ACTIVE 0x0000 #define HCI_CM_ACTIVE 0x0000
#define HCI_CM_HOLD 0x0001 #define HCI_CM_HOLD 0x0001
...@@ -199,6 +200,14 @@ enum { ...@@ -199,6 +200,14 @@ enum {
#define HCI_LM_RELIABLE 0x0010 #define HCI_LM_RELIABLE 0x0010
#define HCI_LM_SECURE 0x0020 #define HCI_LM_SECURE 0x0020
/* Authentication types */
#define HCI_AT_NO_BONDING 0x00
#define HCI_AT_NO_BONDING_MITM 0x01
#define HCI_AT_DEDICATED_BONDING 0x02
#define HCI_AT_DEDICATED_BONDING_MITM 0x03
#define HCI_AT_GENERAL_BONDING 0x04
#define HCI_AT_GENERAL_BONDING_MITM 0x05
/* ----- HCI Commands ---- */ /* ----- HCI Commands ---- */
#define HCI_OP_INQUIRY 0x0401 #define HCI_OP_INQUIRY 0x0401
struct hci_cp_inquiry { struct hci_cp_inquiry {
...@@ -402,6 +411,17 @@ struct hci_rp_write_link_policy { ...@@ -402,6 +411,17 @@ struct hci_rp_write_link_policy {
__le16 handle; __le16 handle;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_OP_READ_DEF_LINK_POLICY 0x080e
struct hci_rp_read_def_link_policy {
__u8 status;
__le16 policy;
} __attribute__ ((packed));
#define HCI_OP_WRITE_DEF_LINK_POLICY 0x080f
struct hci_cp_write_def_link_policy {
__le16 policy;
} __attribute__ ((packed));
#define HCI_OP_SNIFF_SUBRATE 0x0811 #define HCI_OP_SNIFF_SUBRATE 0x0811
struct hci_cp_sniff_subrate { struct hci_cp_sniff_subrate {
__le16 handle; __le16 handle;
...@@ -501,6 +521,17 @@ struct hci_cp_host_buffer_size { ...@@ -501,6 +521,17 @@ struct hci_cp_host_buffer_size {
__le16 sco_max_pkt; __le16 sco_max_pkt;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_OP_READ_SSP_MODE 0x0c55
struct hci_rp_read_ssp_mode {
__u8 status;
__u8 mode;
} __attribute__ ((packed));
#define HCI_OP_WRITE_SSP_MODE 0x0c56
struct hci_cp_write_ssp_mode {
__u8 mode;
} __attribute__ ((packed));
#define HCI_OP_READ_LOCAL_VERSION 0x1001 #define HCI_OP_READ_LOCAL_VERSION 0x1001
struct hci_rp_read_local_version { struct hci_rp_read_local_version {
__u8 status; __u8 status;
...@@ -696,6 +727,13 @@ struct hci_ev_clock_offset { ...@@ -696,6 +727,13 @@ struct hci_ev_clock_offset {
__le16 clock_offset; __le16 clock_offset;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_PKT_TYPE_CHANGE 0x1d
struct hci_ev_pkt_type_change {
__u8 status;
__le16 handle;
__le16 pkt_type;
} __attribute__ ((packed));
#define HCI_EV_PSCAN_REP_MODE 0x20 #define HCI_EV_PSCAN_REP_MODE 0x20
struct hci_ev_pscan_rep_mode { struct hci_ev_pscan_rep_mode {
bdaddr_t bdaddr; bdaddr_t bdaddr;
...@@ -774,6 +812,23 @@ struct extended_inquiry_info { ...@@ -774,6 +812,23 @@ struct extended_inquiry_info {
__u8 data[240]; __u8 data[240];
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_IO_CAPA_REQUEST 0x31
struct hci_ev_io_capa_request {
bdaddr_t bdaddr;
} __attribute__ ((packed));
#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36
struct hci_ev_simple_pair_complete {
__u8 status;
bdaddr_t bdaddr;
} __attribute__ ((packed));
#define HCI_EV_REMOTE_HOST_FEATURES 0x3d
struct hci_ev_remote_host_features {
bdaddr_t bdaddr;
__u8 features[8];
} __attribute__ ((packed));
/* Internal events generated by Bluetooth stack */ /* Internal events generated by Bluetooth stack */
#define HCI_EV_STACK_INTERNAL 0xfd #define HCI_EV_STACK_INTERNAL 0xfd
struct hci_ev_stack_internal { struct hci_ev_stack_internal {
...@@ -951,6 +1006,11 @@ struct hci_conn_info_req { ...@@ -951,6 +1006,11 @@ struct hci_conn_info_req {
struct hci_conn_info conn_info[0]; struct hci_conn_info conn_info[0];
}; };
struct hci_auth_info_req {
bdaddr_t bdaddr;
__u8 type;
};
struct hci_inquiry_req { struct hci_inquiry_req {
__u16 dev_id; __u16 dev_id;
__u16 flags; __u16 flags;
......
...@@ -40,6 +40,7 @@ struct inquiry_data { ...@@ -40,6 +40,7 @@ struct inquiry_data {
__u8 dev_class[3]; __u8 dev_class[3];
__le16 clock_offset; __le16 clock_offset;
__s8 rssi; __s8 rssi;
__u8 ssp_mode;
}; };
struct inquiry_entry { struct inquiry_entry {
...@@ -75,6 +76,7 @@ struct hci_dev { ...@@ -75,6 +76,7 @@ struct hci_dev {
__u8 dev_class[3]; __u8 dev_class[3];
__u8 features[8]; __u8 features[8];
__u8 commands[64]; __u8 commands[64];
__u8 ssp_mode;
__u8 hci_ver; __u8 hci_ver;
__u16 hci_rev; __u16 hci_rev;
__u16 manufacturer; __u16 manufacturer;
...@@ -161,9 +163,12 @@ struct hci_conn { ...@@ -161,9 +163,12 @@ struct hci_conn {
__u8 attempt; __u8 attempt;
__u8 dev_class[3]; __u8 dev_class[3];
__u8 features[8]; __u8 features[8];
__u8 ssp_mode;
__u16 interval; __u16 interval;
__u16 pkt_type;
__u16 link_policy; __u16 link_policy;
__u32 link_mode; __u32 link_mode;
__u8 auth_type;
__u8 power_save; __u8 power_save;
unsigned long pend; unsigned long pend;
...@@ -344,7 +349,7 @@ static inline void hci_conn_put(struct hci_conn *conn) ...@@ -344,7 +349,7 @@ static inline void hci_conn_put(struct hci_conn *conn)
if (conn->state == BT_CONNECTED) { if (conn->state == BT_CONNECTED) {
timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT); timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT);
if (!conn->out) if (!conn->out)
timeo *= 2; timeo *= 5;
} else } else
timeo = msecs_to_jiffies(10); timeo = msecs_to_jiffies(10);
} else } else
...@@ -418,6 +423,7 @@ int hci_get_dev_list(void __user *arg); ...@@ -418,6 +423,7 @@ int hci_get_dev_list(void __user *arg);
int hci_get_dev_info(void __user *arg); int hci_get_dev_info(void __user *arg);
int hci_get_conn_list(void __user *arg); int hci_get_conn_list(void __user *arg);
int hci_get_conn_info(struct hci_dev *hdev, void __user *arg); int hci_get_conn_info(struct hci_dev *hdev, void __user *arg);
int hci_get_auth_info(struct hci_dev *hdev, void __user *arg);
int hci_inquiry(void __user *arg); int hci_inquiry(void __user *arg);
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
...@@ -459,6 +465,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn); ...@@ -459,6 +465,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF) #define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF)
#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) #define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO) #define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO)
#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR)
/* ----- HCI protocols ----- */ /* ----- HCI protocols ----- */
struct hci_proto { struct hci_proto {
...@@ -474,7 +481,7 @@ struct hci_proto { ...@@ -474,7 +481,7 @@ struct hci_proto {
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 (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb);
int (*auth_cfm) (struct hci_conn *conn, __u8 status); int (*auth_cfm) (struct hci_conn *conn, __u8 status);
int (*encrypt_cfm) (struct hci_conn *conn, __u8 status); int (*encrypt_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) static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
...@@ -532,17 +539,17 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) ...@@ -532,17 +539,17 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
hp->auth_cfm(conn, status); hp->auth_cfm(conn, status);
} }
static inline void hci_proto_encrypt_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; register struct hci_proto *hp;
hp = hci_proto[HCI_PROTO_L2CAP]; hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->encrypt_cfm) if (hp && hp->encrypt_cfm)
hp->encrypt_cfm(conn, status); hp->encrypt_cfm(conn, status, encrypt);
hp = hci_proto[HCI_PROTO_SCO]; hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->encrypt_cfm) if (hp && hp->encrypt_cfm)
hp->encrypt_cfm(conn, status); hp->encrypt_cfm(conn, status, encrypt);
} }
int hci_register_proto(struct hci_proto *hproto); int hci_register_proto(struct hci_proto *hproto);
...@@ -579,7 +586,7 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encr ...@@ -579,7 +586,7 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encr
{ {
struct list_head *p; struct list_head *p;
hci_proto_encrypt_cfm(conn, status); hci_proto_encrypt_cfm(conn, status, encrypt);
read_lock_bh(&hci_cb_list_lock); read_lock_bh(&hci_cb_list_lock);
list_for_each(p, &hci_cb_list) { list_for_each(p, &hci_cb_list) {
......
...@@ -180,7 +180,9 @@ struct rfcomm_dlc { ...@@ -180,7 +180,9 @@ struct rfcomm_dlc {
u8 addr; u8 addr;
u8 priority; u8 priority;
u8 v24_sig; u8 v24_sig;
u8 remote_v24_sig;
u8 mscex; u8 mscex;
u8 out;
u32 link_mode; u32 link_mode;
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <net/sock.h> #include <net/sock.h>
#include <asm/ioctls.h>
#if defined(CONFIG_KMOD) #if defined(CONFIG_KMOD)
#include <linux/kmod.h> #include <linux/kmod.h>
...@@ -48,7 +49,7 @@ ...@@ -48,7 +49,7 @@
#define BT_DBG(D...) #define BT_DBG(D...)
#endif #endif
#define VERSION "2.11" #define VERSION "2.12"
/* Bluetooth sockets */ /* Bluetooth sockets */
#define BT_MAX_PROTO 8 #define BT_MAX_PROTO 8
...@@ -266,6 +267,8 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -266,6 +267,8 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
skb_reset_transport_header(skb); skb_reset_transport_header(skb);
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
if (err == 0)
sock_recv_timestamp(msg, sk, skb);
skb_free_datagram(sk, skb); skb_free_datagram(sk, skb);
...@@ -329,6 +332,54 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w ...@@ -329,6 +332,54 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
} }
EXPORT_SYMBOL(bt_sock_poll); EXPORT_SYMBOL(bt_sock_poll);
int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
struct sk_buff *skb;
long amount;
int err;
BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg);
switch (cmd) {
case TIOCOUTQ:
if (sk->sk_state == BT_LISTEN)
return -EINVAL;
amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
if (amount < 0)
amount = 0;
err = put_user(amount, (int __user *) arg);
break;
case TIOCINQ:
if (sk->sk_state == BT_LISTEN)
return -EINVAL;
lock_sock(sk);
skb = skb_peek(&sk->sk_receive_queue);
amount = skb ? skb->len : 0;
release_sock(sk);
err = put_user(amount, (int __user *) arg);
break;
case SIOCGSTAMP:
err = sock_get_timestamp(sk, (struct timeval __user *) arg);
break;
case SIOCGSTAMPNS:
err = sock_get_timestampns(sk, (struct timespec __user *) arg);
break;
default:
err = -ENOIOCTLCMD;
break;
}
return err;
}
EXPORT_SYMBOL(bt_sock_ioctl);
int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo) int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
......
...@@ -503,6 +503,11 @@ static int bnep_session(void *arg) ...@@ -503,6 +503,11 @@ static int bnep_session(void *arg)
/* Delete network device */ /* Delete network device */
unregister_netdev(dev); unregister_netdev(dev);
/* Wakeup user-space polling for socket errors */
s->sock->sk->sk_err = EUNATCH;
wake_up_interruptible(s->sock->sk->sk_sleep);
/* Release the socket */ /* Release the socket */
fput(s->sock->file); fput(s->sock->file);
......
...@@ -59,24 +59,31 @@ void hci_acl_connect(struct hci_conn *conn) ...@@ -59,24 +59,31 @@ void hci_acl_connect(struct hci_conn *conn)
BT_DBG("%p", conn); BT_DBG("%p", conn);
conn->state = BT_CONNECT; conn->state = BT_CONNECT;
conn->out = 1; conn->out = 1;
conn->link_mode = HCI_LM_MASTER; conn->link_mode = HCI_LM_MASTER;
conn->attempt++; conn->attempt++;
conn->link_policy = hdev->link_policy;
memset(&cp, 0, sizeof(cp)); memset(&cp, 0, sizeof(cp));
bacpy(&cp.bdaddr, &conn->dst); bacpy(&cp.bdaddr, &conn->dst);
cp.pscan_rep_mode = 0x02; cp.pscan_rep_mode = 0x02;
if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst)) && if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst))) {
inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
cp.pscan_rep_mode = ie->data.pscan_rep_mode; cp.pscan_rep_mode = ie->data.pscan_rep_mode;
cp.pscan_mode = ie->data.pscan_mode; cp.pscan_mode = ie->data.pscan_mode;
cp.clock_offset = ie->data.clock_offset | cpu_to_le16(0x8000); cp.clock_offset = ie->data.clock_offset |
cpu_to_le16(0x8000);
}
memcpy(conn->dev_class, ie->data.dev_class, 3); memcpy(conn->dev_class, ie->data.dev_class, 3);
conn->ssp_mode = ie->data.ssp_mode;
} }
cp.pkt_type = cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK); cp.pkt_type = cpu_to_le16(conn->pkt_type);
if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)) if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
cp.role_switch = 0x01; cp.role_switch = 0x01;
else else
...@@ -122,7 +129,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) ...@@ -122,7 +129,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
conn->out = 1; conn->out = 1;
cp.handle = cpu_to_le16(handle); cp.handle = cpu_to_le16(handle);
cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); cp.pkt_type = cpu_to_le16(conn->pkt_type);
hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp); hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);
} }
...@@ -138,7 +145,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) ...@@ -138,7 +145,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
conn->out = 1; conn->out = 1;
cp.handle = cpu_to_le16(handle); cp.handle = cpu_to_le16(handle);
cp.pkt_type = cpu_to_le16(hdev->esco_type); cp.pkt_type = cpu_to_le16(conn->pkt_type);
cp.tx_bandwidth = cpu_to_le32(0x00001f40); cp.tx_bandwidth = cpu_to_le32(0x00001f40);
cp.rx_bandwidth = cpu_to_le32(0x00001f40); cp.rx_bandwidth = cpu_to_le32(0x00001f40);
...@@ -163,11 +170,13 @@ static void hci_conn_timeout(unsigned long arg) ...@@ -163,11 +170,13 @@ static void hci_conn_timeout(unsigned long arg)
switch (conn->state) { switch (conn->state) {
case BT_CONNECT: case BT_CONNECT:
case BT_CONNECT2:
if (conn->type == ACL_LINK) if (conn->type == ACL_LINK)
hci_acl_connect_cancel(conn); hci_acl_connect_cancel(conn);
else else
hci_acl_disconn(conn, 0x13); hci_acl_disconn(conn, 0x13);
break; break;
case BT_CONFIG:
case BT_CONNECTED: case BT_CONNECTED:
hci_acl_disconn(conn, 0x13); hci_acl_disconn(conn, 0x13);
break; break;
...@@ -199,13 +208,28 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) ...@@ -199,13 +208,28 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
return NULL; return NULL;
bacpy(&conn->dst, dst); bacpy(&conn->dst, dst);
conn->hdev = hdev; conn->hdev = hdev;
conn->type = type; conn->type = type;
conn->mode = HCI_CM_ACTIVE; conn->mode = HCI_CM_ACTIVE;
conn->state = BT_OPEN; conn->state = BT_OPEN;
conn->power_save = 1; conn->power_save = 1;
switch (type) {
case ACL_LINK:
conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
break;
case SCO_LINK:
if (lmp_esco_capable(hdev))
conn->pkt_type = hdev->esco_type & SCO_ESCO_MASK;
else
conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;
break;
case ESCO_LINK:
conn->pkt_type = hdev->esco_type;
break;
}
skb_queue_head_init(&conn->data_q); skb_queue_head_init(&conn->data_q);
setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);
...@@ -221,8 +245,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) ...@@ -221,8 +245,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
if (hdev->notify) if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
hci_conn_add_sysfs(conn);
tasklet_enable(&hdev->tx_task); tasklet_enable(&hdev->tx_task);
return conn; return conn;
...@@ -254,12 +276,14 @@ int hci_conn_del(struct hci_conn *conn) ...@@ -254,12 +276,14 @@ int hci_conn_del(struct hci_conn *conn)
} }
tasklet_disable(&hdev->tx_task); tasklet_disable(&hdev->tx_task);
hci_conn_hash_del(hdev, conn); hci_conn_hash_del(hdev, conn);
if (hdev->notify) if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
tasklet_enable(&hdev->tx_task); tasklet_enable(&hdev->tx_task);
skb_queue_purge(&conn->data_q); skb_queue_purge(&conn->data_q);
hci_conn_del_sysfs(conn);
return 0; return 0;
} }
...@@ -355,13 +379,21 @@ int hci_conn_auth(struct hci_conn *conn) ...@@ -355,13 +379,21 @@ int hci_conn_auth(struct hci_conn *conn)
{ {
BT_DBG("conn %p", conn); BT_DBG("conn %p", conn);
if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0) {
if (!(conn->auth_type & 0x01)) {
conn->auth_type = HCI_AT_GENERAL_BONDING_MITM;
conn->link_mode &= ~HCI_LM_AUTH;
}
}
if (conn->link_mode & HCI_LM_AUTH) if (conn->link_mode & HCI_LM_AUTH)
return 1; return 1;
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
struct hci_cp_auth_requested cp; struct hci_cp_auth_requested cp;
cp.handle = cpu_to_le16(conn->handle); cp.handle = cpu_to_le16(conn->handle);
hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
sizeof(cp), &cp);
} }
return 0; return 0;
} }
...@@ -373,7 +405,7 @@ int hci_conn_encrypt(struct hci_conn *conn) ...@@ -373,7 +405,7 @@ int hci_conn_encrypt(struct hci_conn *conn)
BT_DBG("conn %p", conn); BT_DBG("conn %p", conn);
if (conn->link_mode & HCI_LM_ENCRYPT) if (conn->link_mode & HCI_LM_ENCRYPT)
return 1; return hci_conn_auth(conn);
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
return 0; return 0;
...@@ -382,7 +414,8 @@ int hci_conn_encrypt(struct hci_conn *conn) ...@@ -382,7 +414,8 @@ int hci_conn_encrypt(struct hci_conn *conn)
struct hci_cp_set_conn_encrypt cp; struct hci_cp_set_conn_encrypt cp;
cp.handle = cpu_to_le16(conn->handle); cp.handle = cpu_to_le16(conn->handle);
cp.encrypt = 1; cp.encrypt = 1;
hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp); hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
sizeof(cp), &cp);
} }
return 0; return 0;
} }
...@@ -396,7 +429,8 @@ int hci_conn_change_link_key(struct hci_conn *conn) ...@@ -396,7 +429,8 @@ int hci_conn_change_link_key(struct hci_conn *conn)
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
struct hci_cp_change_conn_link_key cp; struct hci_cp_change_conn_link_key cp;
cp.handle = cpu_to_le16(conn->handle); cp.handle = cpu_to_le16(conn->handle);
hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp); hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
sizeof(cp), &cp);
} }
return 0; return 0;
} }
...@@ -498,6 +532,8 @@ void hci_conn_hash_flush(struct hci_dev *hdev) ...@@ -498,6 +532,8 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
c->state = BT_CLOSED; c->state = BT_CLOSED;
hci_conn_del_sysfs(c);
hci_proto_disconn_ind(c, 0x16); hci_proto_disconn_ind(c, 0x16);
hci_conn_del(c); hci_conn_del(c);
} }
...@@ -600,3 +636,23 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg) ...@@ -600,3 +636,23 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0; return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
} }
int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
{
struct hci_auth_info_req req;
struct hci_conn *conn;
if (copy_from_user(&req, arg, sizeof(req)))
return -EFAULT;
hci_dev_lock_bh(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr);
if (conn)
req.type = conn->auth_type;
hci_dev_unlock_bh(hdev);
if (!conn)
return -ENOENT;
return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0;
}
...@@ -279,10 +279,20 @@ static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt) ...@@ -279,10 +279,20 @@ static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
BT_DBG("%s %x", hdev->name, encrypt); BT_DBG("%s %x", hdev->name, encrypt);
/* Authentication */ /* Encryption */
hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt); hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
} }
static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt)
{
__le16 policy = cpu_to_le16(opt);
BT_DBG("%s %x", hdev->name, opt);
/* Default link policy */
hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
}
/* Get HCI device by index. /* Get HCI device by index.
* Device is held on return. */ * Device is held on return. */
struct hci_dev *hci_dev_get(int index) struct hci_dev *hci_dev_get(int index)
...@@ -694,32 +704,35 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) ...@@ -694,32 +704,35 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
msecs_to_jiffies(HCI_INIT_TIMEOUT)); msecs_to_jiffies(HCI_INIT_TIMEOUT));
break; break;
case HCISETPTYPE:
hdev->pkt_type = (__u16) dr.dev_opt;
break;
case HCISETLINKPOL: case HCISETLINKPOL:
hdev->link_policy = (__u16) dr.dev_opt; err = hci_request(hdev, hci_linkpol_req, dr.dev_opt,
msecs_to_jiffies(HCI_INIT_TIMEOUT));
break; break;
case HCISETLINKMODE: case HCISETLINKMODE:
hdev->link_mode = ((__u16) dr.dev_opt) & (HCI_LM_MASTER | HCI_LM_ACCEPT); hdev->link_mode = ((__u16) dr.dev_opt) &
(HCI_LM_MASTER | HCI_LM_ACCEPT);
break;
case HCISETPTYPE:
hdev->pkt_type = (__u16) dr.dev_opt;
break; break;
case HCISETACLMTU: case HCISETACLMTU:
hdev->acl_mtu = *((__u16 *)&dr.dev_opt + 1); hdev->acl_mtu = *((__u16 *) &dr.dev_opt + 1);
hdev->acl_pkts = *((__u16 *)&dr.dev_opt + 0); hdev->acl_pkts = *((__u16 *) &dr.dev_opt + 0);
break; break;
case HCISETSCOMTU: case HCISETSCOMTU:
hdev->sco_mtu = *((__u16 *)&dr.dev_opt + 1); hdev->sco_mtu = *((__u16 *) &dr.dev_opt + 1);
hdev->sco_pkts = *((__u16 *)&dr.dev_opt + 0); hdev->sco_pkts = *((__u16 *) &dr.dev_opt + 0);
break; break;
default: default:
err = -EINVAL; err = -EINVAL;
break; break;
} }
hci_dev_put(hdev); hci_dev_put(hdev);
return err; return err;
} }
...@@ -1270,9 +1283,12 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int ...@@ -1270,9 +1283,12 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
struct hci_conn *c; struct hci_conn *c;
c = list_entry(p, struct hci_conn, list); c = list_entry(p, struct hci_conn, list);
if (c->type != type || c->state != BT_CONNECTED if (c->type != type || skb_queue_empty(&c->data_q))
|| skb_queue_empty(&c->data_q)) continue;
if (c->state != BT_CONNECTED && c->state != BT_CONFIG)
continue; continue;
num++; num++;
if (c->sent < min) { if (c->sent < min) {
......
This diff is collapsed.
...@@ -193,19 +193,11 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign ...@@ -193,19 +193,11 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
return 0; return 0;
case HCISETSECMGR:
if (!capable(CAP_NET_ADMIN))
return -EACCES;
if (arg)
set_bit(HCI_SECMGR, &hdev->flags);
else
clear_bit(HCI_SECMGR, &hdev->flags);
return 0;
case HCIGETCONNINFO: case HCIGETCONNINFO:
return hci_get_conn_info(hdev, (void __user *)arg); return hci_get_conn_info(hdev, (void __user *) arg);
case HCIGETAUTHINFO:
return hci_get_auth_info(hdev, (void __user *) arg);
default: default:
if (hdev->ioctl) if (hdev->ioctl)
...@@ -217,7 +209,7 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign ...@@ -217,7 +209,7 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *) arg;
int err; int err;
BT_DBG("cmd %x arg %lx", cmd, arg); BT_DBG("cmd %x arg %lx", cmd, arg);
......
...@@ -113,11 +113,13 @@ static ssize_t show_inquiry_cache(struct device *dev, struct device_attribute *a ...@@ -113,11 +113,13 @@ static ssize_t show_inquiry_cache(struct device *dev, struct device_attribute *a
struct inquiry_data *data = &e->data; struct inquiry_data *data = &e->data;
bdaddr_t bdaddr; bdaddr_t bdaddr;
baswap(&bdaddr, &data->bdaddr); baswap(&bdaddr, &data->bdaddr);
n += sprintf(buf + n, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %u\n", n += sprintf(buf + n, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
batostr(&bdaddr), batostr(&bdaddr),
data->pscan_rep_mode, data->pscan_period_mode, data->pscan_mode, data->pscan_rep_mode, data->pscan_period_mode,
data->dev_class[2], data->dev_class[1], data->dev_class[0], data->pscan_mode, data->dev_class[2],
__le16_to_cpu(data->clock_offset), data->rssi, e->timestamp); data->dev_class[1], data->dev_class[0],
__le16_to_cpu(data->clock_offset),
data->rssi, data->ssp_mode, e->timestamp);
} }
hci_dev_unlock_bh(hdev); hci_dev_unlock_bh(hdev);
...@@ -249,15 +251,28 @@ static ssize_t show_conn_address(struct device *dev, struct device_attribute *at ...@@ -249,15 +251,28 @@ static ssize_t show_conn_address(struct device *dev, struct device_attribute *at
return sprintf(buf, "%s\n", batostr(&bdaddr)); return sprintf(buf, "%s\n", batostr(&bdaddr));
} }
static ssize_t show_conn_features(struct device *dev, struct device_attribute *attr, char *buf)
{
struct hci_conn *conn = dev_get_drvdata(dev);
return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
conn->features[0], conn->features[1],
conn->features[2], conn->features[3],
conn->features[4], conn->features[5],
conn->features[6], conn->features[7]);
}
#define CONN_ATTR(_name,_mode,_show,_store) \ #define CONN_ATTR(_name,_mode,_show,_store) \
struct device_attribute conn_attr_##_name = __ATTR(_name,_mode,_show,_store) struct device_attribute conn_attr_##_name = __ATTR(_name,_mode,_show,_store)
static CONN_ATTR(type, S_IRUGO, show_conn_type, NULL); static CONN_ATTR(type, S_IRUGO, show_conn_type, NULL);
static CONN_ATTR(address, S_IRUGO, show_conn_address, NULL); static CONN_ATTR(address, S_IRUGO, show_conn_address, NULL);
static CONN_ATTR(features, S_IRUGO, show_conn_features, NULL);
static struct device_attribute *conn_attrs[] = { static struct device_attribute *conn_attrs[] = {
&conn_attr_type, &conn_attr_type,
&conn_attr_address, &conn_attr_address,
&conn_attr_features,
NULL NULL
}; };
...@@ -296,7 +311,6 @@ static void add_conn(struct work_struct *work) ...@@ -296,7 +311,6 @@ static void add_conn(struct work_struct *work)
void hci_conn_add_sysfs(struct hci_conn *conn) void hci_conn_add_sysfs(struct hci_conn *conn)
{ {
struct hci_dev *hdev = conn->hdev; struct hci_dev *hdev = conn->hdev;
bdaddr_t *ba = &conn->dst;
BT_DBG("conn %p", conn); BT_DBG("conn %p", conn);
...@@ -305,11 +319,8 @@ void hci_conn_add_sysfs(struct hci_conn *conn) ...@@ -305,11 +319,8 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
conn->dev.release = bt_release; conn->dev.release = bt_release;
snprintf(conn->dev.bus_id, BUS_ID_SIZE, snprintf(conn->dev.bus_id, BUS_ID_SIZE, "%s:%d",
"%s%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X", hdev->name, conn->handle);
conn->type == ACL_LINK ? "acl" : "sco",
ba->b[5], ba->b[4], ba->b[3],
ba->b[2], ba->b[1], ba->b[0]);
dev_set_drvdata(&conn->dev, conn); dev_set_drvdata(&conn->dev, conn);
......
...@@ -581,6 +581,12 @@ static int hidp_session(void *arg) ...@@ -581,6 +581,12 @@ static int hidp_session(void *arg)
hid_free_device(session->hid); hid_free_device(session->hid);
} }
/* Wakeup user-space polling for socket errors */
session->intr_sock->sk->sk_err = EUNATCH;
session->ctrl_sock->sk->sk_err = EUNATCH;
hidp_schedule(session);
fput(session->intr_sock->file); fput(session->intr_sock->file);
wait_event_timeout(*(ctrl_sk->sk_sleep), wait_event_timeout(*(ctrl_sk->sk_sleep),
...@@ -879,6 +885,10 @@ int hidp_del_connection(struct hidp_conndel_req *req) ...@@ -879,6 +885,10 @@ int hidp_del_connection(struct hidp_conndel_req *req)
skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->ctrl_transmit);
skb_queue_purge(&session->intr_transmit); skb_queue_purge(&session->intr_transmit);
/* Wakeup user-space polling for socket errors */
session->intr_sock->sk->sk_err = EUNATCH;
session->ctrl_sock->sk->sk_err = EUNATCH;
/* Kill session thread */ /* Kill session thread */
atomic_inc(&session->terminate); atomic_inc(&session->terminate);
hidp_schedule(session); hidp_schedule(session);
......
This diff is collapsed.
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
#define BT_DBG(D...) #define BT_DBG(D...)
#endif #endif
#define VERSION "1.8" #define VERSION "1.10"
static int disable_cfc = 0; static int disable_cfc = 0;
static int channel_mtu = -1; static int channel_mtu = -1;
...@@ -228,6 +228,21 @@ static int rfcomm_l2sock_create(struct socket **sock) ...@@ -228,6 +228,21 @@ static int rfcomm_l2sock_create(struct socket **sock)
return err; return err;
} }
static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d)
{
struct sock *sk = d->session->sock->sk;
if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) {
if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon))
return 1;
} else if (d->link_mode & RFCOMM_LM_AUTH) {
if (!hci_conn_auth(l2cap_pi(sk)->conn->hcon))
return 1;
}
return 0;
}
/* ---- RFCOMM DLCs ---- */ /* ---- RFCOMM DLCs ---- */
static void rfcomm_dlc_timeout(unsigned long arg) static void rfcomm_dlc_timeout(unsigned long arg)
{ {
...@@ -369,15 +384,23 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, ...@@ -369,15 +384,23 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
d->addr = __addr(s->initiator, dlci); d->addr = __addr(s->initiator, dlci);
d->priority = 7; d->priority = 7;
d->state = BT_CONFIG; d->state = BT_CONFIG;
rfcomm_dlc_link(s, d); rfcomm_dlc_link(s, d);
d->out = 1;
d->mtu = s->mtu; d->mtu = s->mtu;
d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc; d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
if (s->state == BT_CONNECTED) if (s->state == BT_CONNECTED) {
rfcomm_send_pn(s, 1, d); if (rfcomm_check_link_mode(d))
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
else
rfcomm_send_pn(s, 1, d);
}
rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT); rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
return 0; return 0;
} }
...@@ -1144,21 +1167,6 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci) ...@@ -1144,21 +1167,6 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
return 0; return 0;
} }
static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d)
{
struct sock *sk = d->session->sock->sk;
if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) {
if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon))
return 1;
} else if (d->link_mode & RFCOMM_LM_AUTH) {
if (!hci_conn_auth(l2cap_pi(sk)->conn->hcon))
return 1;
}
return 0;
}
static void rfcomm_dlc_accept(struct rfcomm_dlc *d) static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
{ {
struct sock *sk = d->session->sock->sk; struct sock *sk = d->session->sock->sk;
...@@ -1203,10 +1211,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci) ...@@ -1203,10 +1211,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
if (rfcomm_check_link_mode(d)) { if (rfcomm_check_link_mode(d)) {
set_bit(RFCOMM_AUTH_PENDING, &d->flags); set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
return 0; } else
} rfcomm_dlc_accept(d);
rfcomm_dlc_accept(d);
} }
return 0; return 0;
} }
...@@ -1221,10 +1227,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci) ...@@ -1221,10 +1227,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
if (rfcomm_check_link_mode(d)) { if (rfcomm_check_link_mode(d)) {
set_bit(RFCOMM_AUTH_PENDING, &d->flags); set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
return 0; } else
} rfcomm_dlc_accept(d);
rfcomm_dlc_accept(d);
} else { } else {
rfcomm_send_dm(s, dlci); rfcomm_send_dm(s, dlci);
} }
...@@ -1457,8 +1461,12 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb ...@@ -1457,8 +1461,12 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb
clear_bit(RFCOMM_TX_THROTTLED, &d->flags); clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
rfcomm_dlc_lock(d); rfcomm_dlc_lock(d);
d->remote_v24_sig = msc->v24_sig;
if (d->modem_status) if (d->modem_status)
d->modem_status(d, msc->v24_sig); d->modem_status(d, msc->v24_sig);
rfcomm_dlc_unlock(d); rfcomm_dlc_unlock(d);
rfcomm_send_msc(s, 0, dlci, msc->v24_sig); rfcomm_send_msc(s, 0, dlci, msc->v24_sig);
...@@ -1634,7 +1642,11 @@ static void rfcomm_process_connect(struct rfcomm_session *s) ...@@ -1634,7 +1642,11 @@ static void rfcomm_process_connect(struct rfcomm_session *s)
d = list_entry(p, struct rfcomm_dlc, list); d = list_entry(p, struct rfcomm_dlc, list);
if (d->state == BT_CONFIG) { if (d->state == BT_CONFIG) {
d->mtu = s->mtu; d->mtu = s->mtu;
rfcomm_send_pn(s, 1, d); if (rfcomm_check_link_mode(d)) {
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
} else
rfcomm_send_pn(s, 1, d);
} }
} }
} }
...@@ -1707,7 +1719,11 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s) ...@@ -1707,7 +1719,11 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
if (test_and_clear_bit(RFCOMM_AUTH_ACCEPT, &d->flags)) { if (test_and_clear_bit(RFCOMM_AUTH_ACCEPT, &d->flags)) {
rfcomm_dlc_clear_timer(d); rfcomm_dlc_clear_timer(d);
rfcomm_dlc_accept(d); if (d->out) {
rfcomm_send_pn(s, 1, d);
rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
} else
rfcomm_dlc_accept(d);
if (d->link_mode & RFCOMM_LM_SECURE) { if (d->link_mode & RFCOMM_LM_SECURE) {
struct sock *sk = s->sock->sk; struct sock *sk = s->sock->sk;
hci_conn_change_link_key(l2cap_pi(sk)->conn->hcon); hci_conn_change_link_key(l2cap_pi(sk)->conn->hcon);
...@@ -1715,7 +1731,10 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s) ...@@ -1715,7 +1731,10 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
continue; continue;
} else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) { } else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) {
rfcomm_dlc_clear_timer(d); rfcomm_dlc_clear_timer(d);
rfcomm_send_dm(s, d->dlci); if (!d->out)
rfcomm_send_dm(s, d->dlci);
else
d->state = BT_CLOSED;
__rfcomm_dlc_close(d, ECONNREFUSED); __rfcomm_dlc_close(d, ECONNREFUSED);
continue; continue;
} }
...@@ -1724,7 +1743,7 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s) ...@@ -1724,7 +1743,7 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
continue; continue;
if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) && if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
d->mscex == RFCOMM_MSCEX_OK) d->mscex == RFCOMM_MSCEX_OK)
rfcomm_process_tx(d); rfcomm_process_tx(d);
} }
} }
...@@ -1952,7 +1971,8 @@ static void rfcomm_auth_cfm(struct hci_conn *conn, u8 status) ...@@ -1952,7 +1971,8 @@ static void rfcomm_auth_cfm(struct hci_conn *conn, u8 status)
list_for_each_safe(p, n, &s->dlcs) { list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list); d = list_entry(p, struct rfcomm_dlc, list);
if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) &&
!(conn->link_mode & HCI_LM_ENCRYPT) && !status)
continue; continue;
if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags)) if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
...@@ -1986,6 +2006,14 @@ static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt) ...@@ -1986,6 +2006,14 @@ static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
list_for_each_safe(p, n, &s->dlcs) { list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list); d = list_entry(p, struct rfcomm_dlc, list);
if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) &&
(d->state == BT_CONNECTED ||
d->state == BT_CONFIG) &&
!status && encrypt == 0x00) {
__rfcomm_dlc_close(d, ECONNREFUSED);
continue;
}
if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags)) if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
continue; continue;
......
...@@ -307,13 +307,13 @@ static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int ...@@ -307,13 +307,13 @@ static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int
sk->sk_destruct = rfcomm_sock_destruct; sk->sk_destruct = rfcomm_sock_destruct;
sk->sk_sndtimeo = RFCOMM_CONN_TIMEOUT; sk->sk_sndtimeo = RFCOMM_CONN_TIMEOUT;
sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
sock_reset_flag(sk, SOCK_ZAPPED); sock_reset_flag(sk, SOCK_ZAPPED);
sk->sk_protocol = proto; sk->sk_protocol = proto;
sk->sk_state = BT_OPEN; sk->sk_state = BT_OPEN;
bt_sock_link(&rfcomm_sk_list, sk); bt_sock_link(&rfcomm_sk_list, sk);
...@@ -411,6 +411,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a ...@@ -411,6 +411,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr); bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
rfcomm_pi(sk)->channel = sa->rc_channel; rfcomm_pi(sk)->channel = sa->rc_channel;
d->link_mode = rfcomm_pi(sk)->link_mode;
err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel); err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
if (!err) if (!err)
err = bt_sock_wait_state(sk, BT_CONNECTED, err = bt_sock_wait_state(sk, BT_CONNECTED,
...@@ -686,6 +688,8 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -686,6 +688,8 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
copied += chunk; copied += chunk;
size -= chunk; size -= chunk;
sock_recv_timestamp(msg, sk, skb);
if (!(flags & MSG_PEEK)) { if (!(flags & MSG_PEEK)) {
atomic_sub(chunk, &sk->sk_rmem_alloc); atomic_sub(chunk, &sk->sk_rmem_alloc);
...@@ -791,15 +795,20 @@ static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned lon ...@@ -791,15 +795,20 @@ static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned lon
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int err; int err;
lock_sock(sk); BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg);
err = bt_sock_ioctl(sock, cmd, arg);
if (err == -ENOIOCTLCMD) {
#ifdef CONFIG_BT_RFCOMM_TTY #ifdef CONFIG_BT_RFCOMM_TTY
err = rfcomm_dev_ioctl(sk, cmd, (void __user *)arg); lock_sock(sk);
err = rfcomm_dev_ioctl(sk, cmd, (void __user *) arg);
release_sock(sk);
#else #else
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
#endif #endif
}
release_sock(sk);
return err; return err;
} }
......
...@@ -75,6 +75,8 @@ struct rfcomm_dev { ...@@ -75,6 +75,8 @@ struct rfcomm_dev {
struct device *tty_dev; struct device *tty_dev;
atomic_t wmem_alloc; atomic_t wmem_alloc;
struct sk_buff_head pending;
}; };
static LIST_HEAD(rfcomm_dev_list); static LIST_HEAD(rfcomm_dev_list);
...@@ -262,13 +264,34 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) ...@@ -262,13 +264,34 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
init_waitqueue_head(&dev->wait); init_waitqueue_head(&dev->wait);
tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
skb_queue_head_init(&dev->pending);
rfcomm_dlc_lock(dlc); rfcomm_dlc_lock(dlc);
if (req->flags & (1 << RFCOMM_REUSE_DLC)) {
struct sock *sk = dlc->owner;
struct sk_buff *skb;
BUG_ON(!sk);
rfcomm_dlc_throttle(dlc);
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb);
skb_queue_tail(&dev->pending, skb);
atomic_sub(skb->len, &sk->sk_rmem_alloc);
}
}
dlc->data_ready = rfcomm_dev_data_ready; dlc->data_ready = rfcomm_dev_data_ready;
dlc->state_change = rfcomm_dev_state_change; dlc->state_change = rfcomm_dev_state_change;
dlc->modem_status = rfcomm_dev_modem_status; dlc->modem_status = rfcomm_dev_modem_status;
dlc->owner = dev; dlc->owner = dev;
dev->dlc = dlc; dev->dlc = dlc;
rfcomm_dev_modem_status(dlc, dlc->remote_v24_sig);
rfcomm_dlc_unlock(dlc); rfcomm_dlc_unlock(dlc);
/* It's safe to call __module_get() here because socket already /* It's safe to call __module_get() here because socket already
...@@ -537,11 +560,16 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb) ...@@ -537,11 +560,16 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
struct rfcomm_dev *dev = dlc->owner; struct rfcomm_dev *dev = dlc->owner;
struct tty_struct *tty; struct tty_struct *tty;
if (!dev || !(tty = dev->tty)) { if (!dev) {
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
if (!(tty = dev->tty) || !skb_queue_empty(&dev->pending)) {
skb_queue_tail(&dev->pending, skb);
return;
}
BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len); BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
tty_insert_flip_string(tty, skb->data, skb->len); tty_insert_flip_string(tty, skb->data, skb->len);
...@@ -625,6 +653,30 @@ static void rfcomm_tty_wakeup(unsigned long arg) ...@@ -625,6 +653,30 @@ static void rfcomm_tty_wakeup(unsigned long arg)
#endif #endif
} }
static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev)
{
struct tty_struct *tty = dev->tty;
struct sk_buff *skb;
int inserted = 0;
if (!tty)
return;
BT_DBG("dev %p tty %p", dev, tty);
rfcomm_dlc_lock(dev->dlc);
while ((skb = skb_dequeue(&dev->pending))) {
inserted += tty_insert_flip_string(tty, skb->data, skb->len);
kfree_skb(skb);
}
rfcomm_dlc_unlock(dev->dlc);
if (inserted > 0)
tty_flip_buffer_push(tty);
}
static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
...@@ -689,6 +741,10 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) ...@@ -689,6 +741,10 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
if (err == 0) if (err == 0)
device_move(dev->tty_dev, rfcomm_get_device(dev)); device_move(dev->tty_dev, rfcomm_get_device(dev));
rfcomm_tty_copy_pending(dev);
rfcomm_dlc_unthrottle(dev->dlc);
return err; return err;
} }
...@@ -1121,6 +1177,7 @@ int rfcomm_init_ttys(void) ...@@ -1121,6 +1177,7 @@ int rfcomm_init_ttys(void)
rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
rfcomm_tty_driver->init_termios = tty_std_termios; rfcomm_tty_driver->init_termios = tty_std_termios;
rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
if (tty_register_driver(rfcomm_tty_driver)) { if (tty_register_driver(rfcomm_tty_driver)) {
......
...@@ -53,7 +53,9 @@ ...@@ -53,7 +53,9 @@
#define BT_DBG(D...) #define BT_DBG(D...)
#endif #endif
#define VERSION "0.5" #define VERSION "0.6"
static int disable_esco = 0;
static const struct proto_ops sco_sock_ops; static const struct proto_ops sco_sock_ops;
...@@ -193,7 +195,10 @@ static int sco_connect(struct sock *sk) ...@@ -193,7 +195,10 @@ static int sco_connect(struct sock *sk)
err = -ENOMEM; err = -ENOMEM;
type = lmp_esco_capable(hdev) ? ESCO_LINK : SCO_LINK; if (lmp_esco_capable(hdev) && !disable_esco)
type = ESCO_LINK;
else
type = SCO_LINK;
hcon = hci_connect(hdev, type, dst); hcon = hci_connect(hdev, type, dst);
if (!hcon) if (!hcon)
...@@ -921,7 +926,7 @@ static const struct proto_ops sco_sock_ops = { ...@@ -921,7 +926,7 @@ static const struct proto_ops sco_sock_ops = {
.sendmsg = sco_sock_sendmsg, .sendmsg = sco_sock_sendmsg,
.recvmsg = bt_sock_recvmsg, .recvmsg = bt_sock_recvmsg,
.poll = bt_sock_poll, .poll = bt_sock_poll,
.ioctl = sock_no_ioctl, .ioctl = bt_sock_ioctl,
.mmap = sock_no_mmap, .mmap = sock_no_mmap,
.socketpair = sock_no_socketpair, .socketpair = sock_no_socketpair,
.shutdown = sock_no_shutdown, .shutdown = sock_no_shutdown,
...@@ -994,6 +999,9 @@ static void __exit sco_exit(void) ...@@ -994,6 +999,9 @@ static void __exit sco_exit(void)
module_init(sco_init); module_init(sco_init);
module_exit(sco_exit); module_exit(sco_exit);
module_param(disable_esco, bool, 0644);
MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation");
MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>"); MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION); MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment