Commit 7888b61c authored by John W. Linville's avatar John W. Linville

Merge branch 'for-upstream' of...

Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
parents d9a577c3 71fb4197
...@@ -115,6 +115,9 @@ struct bt_voice { ...@@ -115,6 +115,9 @@ struct bt_voice {
#define BT_VOICE_TRANSPARENT 0x0003 #define BT_VOICE_TRANSPARENT 0x0003
#define BT_VOICE_CVSD_16BIT 0x0060 #define BT_VOICE_CVSD_16BIT 0x0060
#define BT_SNDMTU 12
#define BT_RCVMTU 13
__printf(1, 2) __printf(1, 2)
int bt_info(const char *fmt, ...); int bt_info(const char *fmt, ...);
__printf(1, 2) __printf(1, 2)
......
...@@ -275,6 +275,12 @@ enum { ...@@ -275,6 +275,12 @@ enum {
#define LMP_EXTFEATURES 0x80 #define LMP_EXTFEATURES 0x80
/* Extended LMP features */ /* Extended LMP features */
#define LMP_CSB_MASTER 0x01
#define LMP_CSB_SLAVE 0x02
#define LMP_SYNC_TRAIN 0x04
#define LMP_SYNC_SCAN 0x08
/* Host features */
#define LMP_HOST_SSP 0x01 #define LMP_HOST_SSP 0x01
#define LMP_HOST_LE 0x02 #define LMP_HOST_LE 0x02
#define LMP_HOST_LE_BREDR 0x04 #define LMP_HOST_LE_BREDR 0x04
......
...@@ -798,6 +798,12 @@ void hci_conn_del_sysfs(struct hci_conn *conn); ...@@ -798,6 +798,12 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_transp_capable(dev) ((dev)->features[0][2] & LMP_TRANSPARENT) #define lmp_transp_capable(dev) ((dev)->features[0][2] & LMP_TRANSPARENT)
/* ----- Extended LMP capabilities ----- */ /* ----- Extended LMP capabilities ----- */
#define lmp_csb_master_capable(dev) ((dev)->features[2][0] & LMP_CSB_MASTER)
#define lmp_csb_slave_capable(dev) ((dev)->features[2][0] & LMP_CSB_SLAVE)
#define lmp_sync_train_capable(dev) ((dev)->features[2][0] & LMP_SYNC_TRAIN)
#define lmp_sync_scan_capable(dev) ((dev)->features[2][0] & LMP_SYNC_SCAN)
/* ----- Host capabilities ----- */
#define lmp_host_ssp_capable(dev) ((dev)->features[1][0] & LMP_HOST_SSP) #define lmp_host_ssp_capable(dev) ((dev)->features[1][0] & LMP_HOST_SSP)
#define lmp_host_le_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE)) #define lmp_host_le_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE))
#define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR)) #define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR))
......
...@@ -112,6 +112,9 @@ struct l2cap_conninfo { ...@@ -112,6 +112,9 @@ struct l2cap_conninfo {
#define L2CAP_MOVE_CHAN_CFM_RSP 0x11 #define L2CAP_MOVE_CHAN_CFM_RSP 0x11
#define L2CAP_CONN_PARAM_UPDATE_REQ 0x12 #define L2CAP_CONN_PARAM_UPDATE_REQ 0x12
#define L2CAP_CONN_PARAM_UPDATE_RSP 0x13 #define L2CAP_CONN_PARAM_UPDATE_RSP 0x13
#define L2CAP_LE_CONN_REQ 0x14
#define L2CAP_LE_CONN_RSP 0x15
#define L2CAP_LE_CREDITS 0x16
/* L2CAP extended feature mask */ /* L2CAP extended feature mask */
#define L2CAP_FEAT_FLOWCTL 0x00000001 #define L2CAP_FEAT_FLOWCTL 0x00000001
...@@ -249,6 +252,7 @@ struct l2cap_conn_rsp { ...@@ -249,6 +252,7 @@ struct l2cap_conn_rsp {
#define L2CAP_CID_SMP 0x0006 #define L2CAP_CID_SMP 0x0006
#define L2CAP_CID_DYN_START 0x0040 #define L2CAP_CID_DYN_START 0x0040
#define L2CAP_CID_DYN_END 0xffff #define L2CAP_CID_DYN_END 0xffff
#define L2CAP_CID_LE_DYN_END 0x007f
/* connect/create channel results */ /* connect/create channel results */
#define L2CAP_CR_SUCCESS 0x0000 #define L2CAP_CR_SUCCESS 0x0000
...@@ -257,6 +261,10 @@ struct l2cap_conn_rsp { ...@@ -257,6 +261,10 @@ struct l2cap_conn_rsp {
#define L2CAP_CR_SEC_BLOCK 0x0003 #define L2CAP_CR_SEC_BLOCK 0x0003
#define L2CAP_CR_NO_MEM 0x0004 #define L2CAP_CR_NO_MEM 0x0004
#define L2CAP_CR_BAD_AMP 0x0005 #define L2CAP_CR_BAD_AMP 0x0005
#define L2CAP_CR_AUTHENTICATION 0x0005
#define L2CAP_CR_AUTHORIZATION 0x0006
#define L2CAP_CR_BAD_KEY_SIZE 0x0007
#define L2CAP_CR_ENCRYPTION 0x0008
/* connect/create channel status */ /* connect/create channel status */
#define L2CAP_CS_NO_INFO 0x0000 #define L2CAP_CS_NO_INFO 0x0000
...@@ -321,6 +329,12 @@ struct l2cap_conf_rfc { ...@@ -321,6 +329,12 @@ struct l2cap_conf_rfc {
#define L2CAP_MODE_ERTM 0x03 #define L2CAP_MODE_ERTM 0x03
#define L2CAP_MODE_STREAMING 0x04 #define L2CAP_MODE_STREAMING 0x04
/* Unlike the above this one doesn't actually map to anything that would
* ever be sent over the air. Therefore, use a value that's unlikely to
* ever be used in the BR/EDR configuration phase.
*/
#define L2CAP_MODE_LE_FLOWCTL 0x80
struct l2cap_conf_efs { struct l2cap_conf_efs {
__u8 id; __u8 id;
__u8 stype; __u8 stype;
...@@ -423,6 +437,30 @@ struct l2cap_conn_param_update_rsp { ...@@ -423,6 +437,30 @@ struct l2cap_conn_param_update_rsp {
#define L2CAP_CONN_PARAM_ACCEPTED 0x0000 #define L2CAP_CONN_PARAM_ACCEPTED 0x0000
#define L2CAP_CONN_PARAM_REJECTED 0x0001 #define L2CAP_CONN_PARAM_REJECTED 0x0001
#define L2CAP_LE_MAX_CREDITS 10
#define L2CAP_LE_DEFAULT_MPS 230
struct l2cap_le_conn_req {
__le16 psm;
__le16 scid;
__le16 mtu;
__le16 mps;
__le16 credits;
} __packed;
struct l2cap_le_conn_rsp {
__le16 dcid;
__le16 mtu;
__le16 mps;
__le16 credits;
__le16 result;
} __packed;
struct l2cap_le_credits {
__le16 cid;
__le16 credits;
} __packed;
/* ----- L2CAP channels and connections ----- */ /* ----- L2CAP channels and connections ----- */
struct l2cap_seq_list { struct l2cap_seq_list {
__u16 head; __u16 head;
...@@ -477,6 +515,9 @@ struct l2cap_chan { ...@@ -477,6 +515,9 @@ struct l2cap_chan {
__u16 monitor_timeout; __u16 monitor_timeout;
__u16 mps; __u16 mps;
__u16 tx_credits;
__u16 rx_credits;
__u8 tx_state; __u8 tx_state;
__u8 rx_state; __u8 rx_state;
...@@ -553,6 +594,7 @@ struct l2cap_ops { ...@@ -553,6 +594,7 @@ struct l2cap_ops {
void (*ready) (struct l2cap_chan *chan); void (*ready) (struct l2cap_chan *chan);
void (*defer) (struct l2cap_chan *chan); void (*defer) (struct l2cap_chan *chan);
void (*resume) (struct l2cap_chan *chan); void (*resume) (struct l2cap_chan *chan);
void (*suspend) (struct l2cap_chan *chan);
void (*set_shutdown) (struct l2cap_chan *chan); void (*set_shutdown) (struct l2cap_chan *chan);
long (*get_sndtimeo) (struct l2cap_chan *chan); long (*get_sndtimeo) (struct l2cap_chan *chan);
struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan,
...@@ -654,6 +696,7 @@ enum { ...@@ -654,6 +696,7 @@ enum {
FLAG_EXT_CTRL, FLAG_EXT_CTRL,
FLAG_EFS_ENABLE, FLAG_EFS_ENABLE,
FLAG_DEFER_SETUP, FLAG_DEFER_SETUP,
FLAG_LE_CONN_REQ_SENT,
}; };
enum { enum {
...@@ -809,11 +852,13 @@ static inline long l2cap_chan_no_get_sndtimeo(struct l2cap_chan *chan) ...@@ -809,11 +852,13 @@ static inline long l2cap_chan_no_get_sndtimeo(struct l2cap_chan *chan)
} }
extern bool disable_ertm; extern bool disable_ertm;
extern bool enable_lecoc;
int l2cap_init_sockets(void); int l2cap_init_sockets(void);
void l2cap_cleanup_sockets(void); void l2cap_cleanup_sockets(void);
bool l2cap_is_socket(struct socket *sock); bool l2cap_is_socket(struct socket *sock);
void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan);
void __l2cap_connect_rsp_defer(struct l2cap_chan *chan); void __l2cap_connect_rsp_defer(struct l2cap_chan *chan);
int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm); int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm);
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#define VERSION "2.17" #define VERSION "2.18"
/* Bluetooth sockets */ /* Bluetooth sockets */
#define BT_MAX_PROTO 8 #define BT_MAX_PROTO 8
......
...@@ -1228,7 +1228,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req) ...@@ -1228,7 +1228,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req)
/* If Connectionless Slave Broadcast master role is supported /* If Connectionless Slave Broadcast master role is supported
* enable all necessary events for it. * enable all necessary events for it.
*/ */
if (hdev->features[2][0] & 0x01) { if (lmp_csb_master_capable(hdev)) {
events[1] |= 0x40; /* Triggered Clock Capture */ events[1] |= 0x40; /* Triggered Clock Capture */
events[1] |= 0x80; /* Synchronization Train Complete */ events[1] |= 0x80; /* Synchronization Train Complete */
events[2] |= 0x10; /* Slave Page Response Timeout */ events[2] |= 0x10; /* Slave Page Response Timeout */
...@@ -1238,7 +1238,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req) ...@@ -1238,7 +1238,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req)
/* If Connectionless Slave Broadcast slave role is supported /* If Connectionless Slave Broadcast slave role is supported
* enable all necessary events for it. * enable all necessary events for it.
*/ */
if (hdev->features[2][0] & 0x02) { if (lmp_csb_slave_capable(hdev)) {
events[2] |= 0x01; /* Synchronization Train Received */ events[2] |= 0x01; /* Synchronization Train Received */
events[2] |= 0x02; /* CSB Receive */ events[2] |= 0x02; /* CSB Receive */
events[2] |= 0x04; /* CSB Timeout */ events[2] |= 0x04; /* CSB Timeout */
...@@ -1309,7 +1309,7 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) ...@@ -1309,7 +1309,7 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt)
hci_set_event_mask_page_2(req); hci_set_event_mask_page_2(req);
/* Check for Synchronization Train support */ /* Check for Synchronization Train support */
if (hdev->features[2][0] & 0x04) if (lmp_sync_train_capable(hdev))
hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL); hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL);
} }
......
This diff is collapsed.
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
/* Bluetooth L2CAP sockets. */ /* Bluetooth L2CAP sockets. */
#include <linux/module.h>
#include <linux/export.h> #include <linux/export.h>
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
...@@ -35,6 +36,8 @@ ...@@ -35,6 +36,8 @@
#include "smp.h" #include "smp.h"
bool enable_lecoc;
static struct bt_sock_list l2cap_sk_list = { static struct bt_sock_list l2cap_sk_list = {
.lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock) .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
}; };
...@@ -50,6 +53,32 @@ bool l2cap_is_socket(struct socket *sock) ...@@ -50,6 +53,32 @@ bool l2cap_is_socket(struct socket *sock)
} }
EXPORT_SYMBOL(l2cap_is_socket); EXPORT_SYMBOL(l2cap_is_socket);
static int l2cap_validate_bredr_psm(u16 psm)
{
/* PSM must be odd and lsb of upper byte must be 0 */
if ((psm & 0x0101) != 0x0001)
return -EINVAL;
/* Restrict usage of well-known PSMs */
if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE))
return -EACCES;
return 0;
}
static int l2cap_validate_le_psm(u16 psm)
{
/* Valid LE_PSM ranges are defined only until 0x00ff */
if (psm > 0x00ff)
return -EINVAL;
/* Restrict fixed, SIG assigned PSM values to CAP_NET_BIND_SERVICE */
if (psm <= 0x007f && !capable(CAP_NET_BIND_SERVICE))
return -EACCES;
return 0;
}
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
...@@ -73,11 +102,11 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) ...@@ -73,11 +102,11 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
return -EINVAL; return -EINVAL;
if (bdaddr_type_is_le(la.l2_bdaddr_type)) { if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
/* Connection oriented channels are not supported on LE */ if (!enable_lecoc && la.l2_psm)
if (la.l2_psm)
return -EINVAL; return -EINVAL;
/* We only allow ATT user space socket */ /* We only allow ATT user space socket */
if (la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) if (la.l2_cid &&
la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT))
return -EINVAL; return -EINVAL;
} }
...@@ -91,17 +120,13 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) ...@@ -91,17 +120,13 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
if (la.l2_psm) { if (la.l2_psm) {
__u16 psm = __le16_to_cpu(la.l2_psm); __u16 psm = __le16_to_cpu(la.l2_psm);
/* PSM must be odd and lsb of upper byte must be 0 */ if (la.l2_bdaddr_type == BDADDR_BREDR)
if ((psm & 0x0101) != 0x0001) { err = l2cap_validate_bredr_psm(psm);
err = -EINVAL; else
goto done; err = l2cap_validate_le_psm(psm);
}
/* Restrict usage of well-known PSMs */ if (err)
if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) {
err = -EACCES;
goto done; goto done;
}
} }
if (la.l2_cid) if (la.l2_cid)
...@@ -127,6 +152,9 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) ...@@ -127,6 +152,9 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
bacpy(&chan->src, &la.l2_bdaddr); bacpy(&chan->src, &la.l2_bdaddr);
chan->src_type = la.l2_bdaddr_type; chan->src_type = la.l2_bdaddr_type;
if (chan->psm && bdaddr_type_is_le(chan->src_type))
chan->mode = L2CAP_MODE_LE_FLOWCTL;
chan->state = BT_BOUND; chan->state = BT_BOUND;
sk->sk_state = BT_BOUND; sk->sk_state = BT_BOUND;
...@@ -189,14 +217,17 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, ...@@ -189,14 +217,17 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
return -EINVAL; return -EINVAL;
if (bdaddr_type_is_le(la.l2_bdaddr_type)) { if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
/* Connection oriented channels are not supported on LE */ if (!enable_lecoc && la.l2_psm)
if (la.l2_psm)
return -EINVAL; return -EINVAL;
/* We only allow ATT user space socket */ /* We only allow ATT user space socket */
if (la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) if (la.l2_cid &&
la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT))
return -EINVAL; return -EINVAL;
} }
if (chan->psm && bdaddr_type_is_le(chan->src_type))
chan->mode = L2CAP_MODE_LE_FLOWCTL;
err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid), err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid),
&la.l2_bdaddr, la.l2_bdaddr_type); &la.l2_bdaddr, la.l2_bdaddr_type);
if (err) if (err)
...@@ -234,6 +265,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) ...@@ -234,6 +265,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
switch (chan->mode) { switch (chan->mode) {
case L2CAP_MODE_BASIC: case L2CAP_MODE_BASIC:
case L2CAP_MODE_LE_FLOWCTL:
break; break;
case L2CAP_MODE_ERTM: case L2CAP_MODE_ERTM:
case L2CAP_MODE_STREAMING: case L2CAP_MODE_STREAMING:
...@@ -360,6 +392,16 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, ...@@ -360,6 +392,16 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
switch (optname) { switch (optname) {
case L2CAP_OPTIONS: case L2CAP_OPTIONS:
/* LE sockets should use BT_SNDMTU/BT_RCVMTU, but since
* legacy ATT code depends on getsockopt for
* L2CAP_OPTIONS we need to let this pass.
*/
if (bdaddr_type_is_le(chan->src_type) &&
chan->scid != L2CAP_CID_ATT) {
err = -EINVAL;
break;
}
memset(&opts, 0, sizeof(opts)); memset(&opts, 0, sizeof(opts));
opts.imtu = chan->imtu; opts.imtu = chan->imtu;
opts.omtu = chan->omtu; opts.omtu = chan->omtu;
...@@ -514,6 +556,41 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ...@@ -514,6 +556,41 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
err = -EFAULT; err = -EFAULT;
break; break;
case BT_SNDMTU:
if (!enable_lecoc) {
err = -EPROTONOSUPPORT;
break;
}
if (!bdaddr_type_is_le(chan->src_type)) {
err = -EINVAL;
break;
}
if (sk->sk_state != BT_CONNECTED) {
err = -ENOTCONN;
break;
}
if (put_user(chan->omtu, (u16 __user *) optval))
err = -EFAULT;
break;
case BT_RCVMTU:
if (!enable_lecoc) {
err = -EPROTONOSUPPORT;
break;
}
if (!bdaddr_type_is_le(chan->src_type)) {
err = -EINVAL;
break;
}
if (put_user(chan->imtu, (u16 __user *) optval))
err = -EFAULT;
break;
default: default:
err = -ENOPROTOOPT; err = -ENOPROTOOPT;
break; break;
...@@ -554,6 +631,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, ...@@ -554,6 +631,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
switch (optname) { switch (optname) {
case L2CAP_OPTIONS: case L2CAP_OPTIONS:
if (bdaddr_type_is_le(chan->src_type)) {
err = -EINVAL;
break;
}
if (sk->sk_state == BT_CONNECTED) { if (sk->sk_state == BT_CONNECTED) {
err = -EINVAL; err = -EINVAL;
break; break;
...@@ -585,6 +667,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, ...@@ -585,6 +667,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
chan->mode = opts.mode; chan->mode = opts.mode;
switch (chan->mode) { switch (chan->mode) {
case L2CAP_MODE_LE_FLOWCTL:
break;
case L2CAP_MODE_BASIC: case L2CAP_MODE_BASIC:
clear_bit(CONF_STATE2_DEVICE, &chan->conf_state); clear_bit(CONF_STATE2_DEVICE, &chan->conf_state);
break; break;
...@@ -807,6 +891,47 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ...@@ -807,6 +891,47 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break; break;
case BT_SNDMTU:
if (!enable_lecoc) {
err = -EPROTONOSUPPORT;
break;
}
if (!bdaddr_type_is_le(chan->src_type)) {
err = -EINVAL;
break;
}
/* Setting is not supported as it's the remote side that
* decides this.
*/
err = -EPERM;
break;
case BT_RCVMTU:
if (!enable_lecoc) {
err = -EPROTONOSUPPORT;
break;
}
if (!bdaddr_type_is_le(chan->src_type)) {
err = -EINVAL;
break;
}
if (sk->sk_state == BT_CONNECTED) {
err = -EISCONN;
break;
}
if (get_user(opt, (u32 __user *) optval)) {
err = -EFAULT;
break;
}
chan->imtu = opt;
break;
default: default:
err = -ENOPROTOOPT; err = -ENOPROTOOPT;
break; break;
...@@ -859,10 +984,16 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -859,10 +984,16 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP,
&bt_sk(sk)->flags)) { &bt_sk(sk)->flags)) {
sk->sk_state = BT_CONFIG; if (bdaddr_type_is_le(pi->chan->src_type)) {
pi->chan->state = BT_CONFIG; sk->sk_state = BT_CONNECTED;
pi->chan->state = BT_CONNECTED;
__l2cap_le_connect_rsp_defer(pi->chan);
} else {
sk->sk_state = BT_CONFIG;
pi->chan->state = BT_CONFIG;
__l2cap_connect_rsp_defer(pi->chan);
}
__l2cap_connect_rsp_defer(pi->chan);
err = 0; err = 0;
goto done; goto done;
} }
...@@ -1236,6 +1367,14 @@ static long l2cap_sock_get_sndtimeo_cb(struct l2cap_chan *chan) ...@@ -1236,6 +1367,14 @@ static long l2cap_sock_get_sndtimeo_cb(struct l2cap_chan *chan)
return sk->sk_sndtimeo; return sk->sk_sndtimeo;
} }
static void l2cap_sock_suspend_cb(struct l2cap_chan *chan)
{
struct sock *sk = chan->data;
set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
sk->sk_state_change(sk);
}
static struct l2cap_ops l2cap_chan_ops = { static struct l2cap_ops l2cap_chan_ops = {
.name = "L2CAP Socket Interface", .name = "L2CAP Socket Interface",
.new_connection = l2cap_sock_new_connection_cb, .new_connection = l2cap_sock_new_connection_cb,
...@@ -1246,6 +1385,7 @@ static struct l2cap_ops l2cap_chan_ops = { ...@@ -1246,6 +1385,7 @@ static struct l2cap_ops l2cap_chan_ops = {
.ready = l2cap_sock_ready_cb, .ready = l2cap_sock_ready_cb,
.defer = l2cap_sock_defer_cb, .defer = l2cap_sock_defer_cb,
.resume = l2cap_sock_resume_cb, .resume = l2cap_sock_resume_cb,
.suspend = l2cap_sock_suspend_cb,
.set_shutdown = l2cap_sock_set_shutdown_cb, .set_shutdown = l2cap_sock_set_shutdown_cb,
.get_sndtimeo = l2cap_sock_get_sndtimeo_cb, .get_sndtimeo = l2cap_sock_get_sndtimeo_cb,
.alloc_skb = l2cap_sock_alloc_skb_cb, .alloc_skb = l2cap_sock_alloc_skb_cb,
...@@ -1303,6 +1443,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) ...@@ -1303,6 +1443,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
chan->tx_win_max = pchan->tx_win_max; chan->tx_win_max = pchan->tx_win_max;
chan->sec_level = pchan->sec_level; chan->sec_level = pchan->sec_level;
chan->flags = pchan->flags; chan->flags = pchan->flags;
chan->tx_credits = pchan->tx_credits;
chan->rx_credits = pchan->rx_credits;
security_sk_clone(parent, sk); security_sk_clone(parent, sk);
} else { } else {
...@@ -1469,3 +1611,6 @@ void l2cap_cleanup_sockets(void) ...@@ -1469,3 +1611,6 @@ void l2cap_cleanup_sockets(void)
bt_sock_unregister(BTPROTO_L2CAP); bt_sock_unregister(BTPROTO_L2CAP);
proto_unregister(&l2cap_proto); proto_unregister(&l2cap_proto);
} }
module_param(enable_lecoc, bool, 0644);
MODULE_PARM_DESC(enable_lecoc, "Enable support for LE CoC");
...@@ -750,6 +750,17 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -750,6 +750,17 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
return 0; return 0;
} }
bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level)
{
if (sec_level == BT_SECURITY_LOW)
return true;
if (hcon->sec_level >= sec_level)
return true;
return false;
}
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
{ {
struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_conn *conn = hcon->l2cap_data;
...@@ -761,10 +772,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) ...@@ -761,10 +772,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags))
return 1; return 1;
if (sec_level == BT_SECURITY_LOW) if (smp_sufficient_security(hcon, sec_level))
return 1;
if (hcon->sec_level >= sec_level)
return 1; return 1;
if (hcon->link_mode & HCI_LM_MASTER) if (hcon->link_mode & HCI_LM_MASTER)
......
...@@ -136,6 +136,7 @@ struct smp_chan { ...@@ -136,6 +136,7 @@ struct smp_chan {
}; };
/* SMP Commands */ /* SMP Commands */
bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level);
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); int smp_conn_security(struct hci_conn *hcon, __u8 sec_level);
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb); int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
int smp_distribute_keys(struct l2cap_conn *conn, __u8 force); int smp_distribute_keys(struct l2cap_conn *conn, __u8 force);
......
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