Commit 15f02b91 authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz Committed by Marcel Holtmann

Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode

This adds the initial code for Enhanced Credit Based Mode which
introduces a new socket mode called L2CAP_MODE_EXT_FLOWCTL, which for
the most part work the same as L2CAP_MODE_LE_FLOWCTL but uses different
PDUs to setup the connections and also works over BR/EDR.
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 14572096
...@@ -294,6 +294,8 @@ struct l2cap_conn_rsp { ...@@ -294,6 +294,8 @@ struct l2cap_conn_rsp {
#define L2CAP_CR_LE_ENCRYPTION 0x0008 #define L2CAP_CR_LE_ENCRYPTION 0x0008
#define L2CAP_CR_LE_INVALID_SCID 0x0009 #define L2CAP_CR_LE_INVALID_SCID 0x0009
#define L2CAP_CR_LE_SCID_IN_USE 0X000A #define L2CAP_CR_LE_SCID_IN_USE 0X000A
#define L2CAP_CR_LE_UNACCEPT_PARAMS 0X000B
#define L2CAP_CR_LE_INVALID_PARAMS 0X000C
/* connect/create channel status */ /* connect/create channel status */
#define L2CAP_CS_NO_INFO 0x0000 #define L2CAP_CS_NO_INFO 0x0000
...@@ -962,6 +964,7 @@ void l2cap_cleanup_sockets(void); ...@@ -962,6 +964,7 @@ 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_le_connect_rsp_defer(struct l2cap_chan *chan);
void __l2cap_ecred_conn_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);
...@@ -971,6 +974,7 @@ struct l2cap_chan *l2cap_chan_create(void); ...@@ -971,6 +974,7 @@ struct l2cap_chan *l2cap_chan_create(void);
void l2cap_chan_close(struct l2cap_chan *chan, int reason); void l2cap_chan_close(struct l2cap_chan *chan, int reason);
int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
bdaddr_t *dst, u8 dst_type); bdaddr_t *dst, u8 dst_type);
int l2cap_chan_reconfigure(struct l2cap_chan *chan, __u16 mtu);
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len); int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
void l2cap_chan_busy(struct l2cap_chan *chan, int busy); void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
int l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator); int l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator);
......
This diff is collapsed.
...@@ -232,7 +232,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, ...@@ -232,7 +232,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
return -EINVAL; return -EINVAL;
} }
if (chan->psm && bdaddr_type_is_le(chan->src_type)) if (chan->psm && bdaddr_type_is_le(chan->src_type) && !chan->mode)
chan->mode = L2CAP_MODE_LE_FLOWCTL; 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),
...@@ -273,6 +273,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) ...@@ -273,6 +273,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: case L2CAP_MODE_LE_FLOWCTL:
case L2CAP_MODE_EXT_FLOWCTL:
break; break;
case L2CAP_MODE_ERTM: case L2CAP_MODE_ERTM:
case L2CAP_MODE_STREAMING: case L2CAP_MODE_STREAMING:
...@@ -427,6 +428,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, ...@@ -427,6 +428,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
opts.max_tx = chan->max_tx; opts.max_tx = chan->max_tx;
opts.txwin_size = chan->tx_win; opts.txwin_size = chan->tx_win;
BT_DBG("mode 0x%2.2x", chan->mode);
len = min_t(unsigned int, len, sizeof(opts)); len = min_t(unsigned int, len, sizeof(opts));
if (copy_to_user(optval, (char *) &opts, len)) if (copy_to_user(optval, (char *) &opts, len))
err = -EFAULT; err = -EFAULT;
...@@ -707,6 +710,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, ...@@ -707,6 +710,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
break; break;
} }
BT_DBG("mode 0x%2.2x", chan->mode);
chan->imtu = opts.imtu; chan->imtu = opts.imtu;
chan->omtu = opts.omtu; chan->omtu = opts.omtu;
chan->fcs = opts.fcs; chan->fcs = opts.fcs;
...@@ -939,7 +944,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ...@@ -939,7 +944,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break; break;
} }
if (sk->sk_state == BT_CONNECTED) { if (chan->mode == L2CAP_MODE_LE_FLOWCTL &&
sk->sk_state == BT_CONNECTED) {
err = -EISCONN; err = -EISCONN;
break; break;
} }
...@@ -949,7 +955,12 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ...@@ -949,7 +955,12 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break; break;
} }
chan->imtu = opt; if (chan->mode == L2CAP_MODE_EXT_FLOWCTL &&
sk->sk_state == BT_CONNECTED)
err = l2cap_chan_reconfigure(chan, opt);
else
chan->imtu = opt;
break; break;
default: default:
...@@ -1004,7 +1015,11 @@ static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, ...@@ -1004,7 +1015,11 @@ static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg,
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)) {
if (bdaddr_type_is_le(pi->chan->src_type)) { if (pi->chan->mode == L2CAP_MODE_EXT_FLOWCTL) {
sk->sk_state = BT_CONNECTED;
pi->chan->state = BT_CONNECTED;
__l2cap_ecred_conn_rsp_defer(pi->chan);
} if (bdaddr_type_is_le(pi->chan->src_type)) {
sk->sk_state = BT_CONNECTED; sk->sk_state = BT_CONNECTED;
pi->chan->state = BT_CONNECTED; pi->chan->state = BT_CONNECTED;
__l2cap_le_connect_rsp_defer(pi->chan); __l2cap_le_connect_rsp_defer(pi->chan);
......
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