Commit 5df82859 authored by Marcel Holtmann's avatar Marcel Holtmann Committed by Marcel Holtmann

[Bluetooth] Support responses with zero SCID

According to the Bluetooth specification there is no need to fill in
the SCID on a failing response. Without a SCID the L2CAP core can't
find the corresponding request for it. In the case of the zero SCID
the signal identifier should be used to match the response to its
request.
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 3e797d16
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
#define BT_DBG(D...) #define BT_DBG(D...)
#endif #endif
#define VERSION "2.4" #define VERSION "2.5"
static struct proto_ops l2cap_sock_ops; static struct proto_ops l2cap_sock_ops;
...@@ -74,8 +74,8 @@ static void __l2cap_sock_close(struct sock *sk, int reason); ...@@ -74,8 +74,8 @@ static void __l2cap_sock_close(struct sock *sk, int reason);
static void l2cap_sock_close(struct sock *sk); static void l2cap_sock_close(struct sock *sk);
static void l2cap_sock_kill(struct sock *sk); static void l2cap_sock_kill(struct sock *sk);
static int l2cap_send_req(struct l2cap_conn *conn, u8 code, u16 len, void *data); static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
static int l2cap_send_rsp(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); u8 code, u8 ident, u16 dlen, void *data);
/* ---- L2CAP timers ---- */ /* ---- L2CAP timers ---- */
static void l2cap_sock_timeout(unsigned long arg) static void l2cap_sock_timeout(unsigned long arg)
...@@ -174,6 +174,40 @@ static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, stru ...@@ -174,6 +174,40 @@ static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, stru
write_unlock(&l->lock); write_unlock(&l->lock);
} }
static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
{
u8 id;
/* Get next available identificator.
* 1 - 128 are used by kernel.
* 129 - 199 are reserved.
* 200 - 254 are used by utilities like l2ping, etc.
*/
spin_lock(&conn->lock);
if (++conn->tx_ident > 128)
conn->tx_ident = 1;
id = conn->tx_ident;
spin_unlock(&conn->lock);
return id;
}
static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
{
struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
BT_DBG("code 0x%2.2x", code);
if (!skb)
return -ENOMEM;
return hci_send_acl(conn->hcon, skb, 0);
}
/* ---- Socket interface ---- */ /* ---- Socket interface ---- */
static struct sock *__l2cap_get_sock_by_addr(u16 psm, bdaddr_t *src) static struct sock *__l2cap_get_sock_by_addr(u16 psm, bdaddr_t *src)
{ {
...@@ -286,7 +320,8 @@ static void __l2cap_sock_close(struct sock *sk, int reason) ...@@ -286,7 +320,8 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
l2cap_send_req(conn, L2CAP_DISCONN_REQ, sizeof(req), &req); l2cap_send_cmd(conn, l2cap_get_ident(conn),
L2CAP_DISCONN_REQ, sizeof(req), &req);
} else { } else {
l2cap_chan_del(sk, reason); l2cap_chan_del(sk, reason);
} }
...@@ -365,7 +400,8 @@ static int l2cap_sock_create(struct socket *sock, int protocol) ...@@ -365,7 +400,8 @@ static int l2cap_sock_create(struct socket *sock, int protocol)
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) if (sock->type != SOCK_SEQPACKET &&
sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT; return -ESOCKTNOSUPPORT;
if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW)) if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW))
...@@ -459,9 +495,11 @@ static int l2cap_do_connect(struct sock *sk) ...@@ -459,9 +495,11 @@ static int l2cap_do_connect(struct sock *sk)
if (hcon->state == BT_CONNECTED) { if (hcon->state == BT_CONNECTED) {
if (sk->sk_type == SOCK_SEQPACKET) { if (sk->sk_type == SOCK_SEQPACKET) {
struct l2cap_conn_req req; struct l2cap_conn_req req;
l2cap_pi(sk)->ident = l2cap_get_ident(conn);
req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
req.psm = l2cap_pi(sk)->psm; req.psm = l2cap_pi(sk)->psm;
l2cap_send_req(conn, L2CAP_CONN_REQ, sizeof(req), &req); l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_REQ, sizeof(req), &req);
} else { } else {
l2cap_sock_clear_timer(sk); l2cap_sock_clear_timer(sk);
sk->sk_state = BT_CONNECTED; sk->sk_state = BT_CONNECTED;
...@@ -911,6 +949,25 @@ static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 ...@@ -911,6 +949,25 @@ static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16
return s; return s;
} }
static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident)
{
struct sock *s;
for (s = l->head; s; s = l2cap_pi(s)->next_c) {
if (l2cap_pi(s)->ident == ident)
break;
}
return s;
}
static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident)
{
struct sock *s;
read_lock(&l->lock);
s = __l2cap_get_chan_by_ident(l, ident);
read_unlock(&l->lock);
return s;
}
static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) static u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
{ {
u16 cid = 0x0040; u16 cid = 0x0040;
...@@ -1030,9 +1087,10 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) ...@@ -1030,9 +1087,10 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
sk->sk_state_change(sk); sk->sk_state_change(sk);
} else if (sk->sk_state == BT_CONNECT) { } else if (sk->sk_state == BT_CONNECT) {
struct l2cap_conn_req req; struct l2cap_conn_req req;
l2cap_pi(sk)->ident = l2cap_get_ident(conn);
req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
req.psm = l2cap_pi(sk)->psm; req.psm = l2cap_pi(sk)->psm;
l2cap_send_req(conn, L2CAP_CONN_REQ, sizeof(req), &req); l2cap_send_cmd(conn, l2cap_pi(sk)->ident, L2CAP_CONN_REQ, sizeof(req), &req);
} }
bh_unlock_sock(sk); bh_unlock_sock(sk);
...@@ -1092,27 +1150,6 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -1092,27 +1150,6 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
} }
/* ---- L2CAP signalling commands ---- */ /* ---- L2CAP signalling commands ---- */
static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
{
u8 id;
/* Get next available identificator.
* 1 - 199 are used by kernel.
* 200 - 254 are used by utilities like l2ping, etc
*/
spin_lock(&conn->lock);
if (++conn->tx_ident > 199)
conn->tx_ident = 1;
id = conn->tx_ident;
spin_unlock(&conn->lock);
return id;
}
static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
u8 code, u8 ident, u16 dlen, void *data) u8 code, u8 ident, u16 dlen, void *data)
{ {
...@@ -1171,29 +1208,6 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, ...@@ -1171,29 +1208,6 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
return NULL; return NULL;
} }
static int l2cap_send_req(struct l2cap_conn *conn, u8 code, u16 len, void *data)
{
u8 ident = l2cap_get_ident(conn);
struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
BT_DBG("code 0x%2.2x", code);
if (!skb)
return -ENOMEM;
return hci_send_acl(conn->hcon, skb, 0);
}
static int l2cap_send_rsp(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
{
struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
BT_DBG("code 0x%2.2x", code);
if (!skb)
return -ENOMEM;
return hci_send_acl(conn->hcon, skb, 0);
}
static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val) static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
{ {
struct l2cap_conf_opt *opt = *ptr; struct l2cap_conf_opt *opt = *ptr;
...@@ -1412,7 +1426,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd ...@@ -1412,7 +1426,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
status = L2CAP_CS_AUTHEN_PEND; status = L2CAP_CS_AUTHEN_PEND;
sk->sk_state = BT_CONNECT2; sk->sk_state = BT_CONNECT2;
l2cap_pi(sk)->ident = cmd->ident; l2cap_pi(sk)->ident = cmd->ident;
if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) { if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) {
if (!hci_conn_encrypt(conn->hcon)) if (!hci_conn_encrypt(conn->hcon))
goto done; goto done;
...@@ -1435,7 +1449,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd ...@@ -1435,7 +1449,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
rsp.dcid = __cpu_to_le16(dcid); rsp.dcid = __cpu_to_le16(dcid);
rsp.result = __cpu_to_le16(result); rsp.result = __cpu_to_le16(result);
rsp.status = __cpu_to_le16(status); rsp.status = __cpu_to_le16(status);
l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
return 0; return 0;
} }
...@@ -1453,16 +1467,23 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd ...@@ -1453,16 +1467,23 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) if (scid) {
return 0; if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
return 0;
} else {
if (!(sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident)))
return 0;
}
switch (result) { switch (result) {
case L2CAP_CR_SUCCESS: case L2CAP_CR_SUCCESS:
sk->sk_state = BT_CONFIG; sk->sk_state = BT_CONFIG;
l2cap_pi(sk)->ident = 0;
l2cap_pi(sk)->dcid = dcid; l2cap_pi(sk)->dcid = dcid;
l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, req), req);
break; break;
case L2CAP_CR_PEND: case L2CAP_CR_PEND:
...@@ -1497,12 +1518,14 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr ...@@ -1497,12 +1518,14 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
if (flags & 0x0001) { if (flags & 0x0001) {
/* Incomplete config. Send empty response. */ /* Incomplete config. Send empty response. */
l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp); l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
goto unlock; goto unlock;
} }
/* Complete config. */ /* Complete config. */
l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp); l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
l2cap_build_conf_rsp(sk, rsp, &result), rsp);
if (result) if (result)
goto unlock; goto unlock;
...@@ -1515,7 +1538,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr ...@@ -1515,7 +1538,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
l2cap_chan_ready(sk); l2cap_chan_ready(sk);
} else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) { } else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
u8 req[64]; u8 req[64];
l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, req), req);
} }
unlock: unlock:
...@@ -1550,8 +1574,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr ...@@ -1550,8 +1574,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
* resend config request that we sent earlier. It is * resend config request that we sent earlier. It is
* stupid, but it helps qualification testing which * stupid, but it helps qualification testing which
* expects at least some response from us. */ * expects at least some response from us. */
l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, req), req); l2cap_build_conf_req(sk, req), req);
goto done; goto done;
} }
...@@ -1563,7 +1587,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr ...@@ -1563,7 +1587,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
struct l2cap_disconn_req req; struct l2cap_disconn_req req;
req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
l2cap_send_req(conn, L2CAP_DISCONN_REQ, sizeof(req), &req); l2cap_send_cmd(conn, l2cap_get_ident(conn),
L2CAP_DISCONN_REQ, sizeof(req), &req);
} }
goto done; goto done;
} }
...@@ -1601,7 +1626,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd ...@@ -1601,7 +1626,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp); l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
sk->sk_shutdown = SHUTDOWN_MASK; sk->sk_shutdown = SHUTDOWN_MASK;
...@@ -1645,7 +1670,7 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm ...@@ -1645,7 +1670,7 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
rsp.type = __cpu_to_le16(type); rsp.type = __cpu_to_le16(type);
rsp.result = __cpu_to_le16(L2CAP_IR_NOTSUPP); rsp.result = __cpu_to_le16(L2CAP_IR_NOTSUPP);
l2cap_send_rsp(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp), &rsp); l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp), &rsp);
return 0; return 0;
} }
...@@ -1716,7 +1741,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk ...@@ -1716,7 +1741,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk
break; break;
case L2CAP_ECHO_REQ: case L2CAP_ECHO_REQ:
l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data); l2cap_send_cmd(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
break; break;
case L2CAP_ECHO_RSP: case L2CAP_ECHO_RSP:
...@@ -1742,7 +1767,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk ...@@ -1742,7 +1767,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk
/* FIXME: Map err to a valid reason */ /* FIXME: Map err to a valid reason */
rej.reason = __cpu_to_le16(0); rej.reason = __cpu_to_le16(0);
l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej); l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
} }
data += cmd.len; data += cmd.len;
...@@ -1939,7 +1964,8 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status) ...@@ -1939,7 +1964,8 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
rsp.result = __cpu_to_le16(result); rsp.result = __cpu_to_le16(result);
rsp.status = __cpu_to_le16(0); rsp.status = __cpu_to_le16(0);
l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
bh_unlock_sock(sk); bh_unlock_sock(sk);
} }
...@@ -1985,7 +2011,8 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status) ...@@ -1985,7 +2011,8 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status)
rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
rsp.result = __cpu_to_le16(result); rsp.result = __cpu_to_le16(result);
rsp.status = __cpu_to_le16(0); rsp.status = __cpu_to_le16(0);
l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
bh_unlock_sock(sk); bh_unlock_sock(sk);
} }
...@@ -2237,7 +2264,7 @@ static void __exit l2cap_exit(void) ...@@ -2237,7 +2264,7 @@ static void __exit l2cap_exit(void)
void l2cap_load(void) void l2cap_load(void)
{ {
/* Dummy function to trigger automatic L2CAP module loading by /* Dummy function to trigger automatic L2CAP module loading by
* other modules that use L2CAP sockets but don not use any othe * other modules that use L2CAP sockets but don't use any other
* symbols from it. */ * symbols from it. */
return; return;
} }
......
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