Bluetooth: L2CAP: Add bt_l2cap_chan_disconnect

This adds bt_l2cap_chan_disconnect which can be used to disconnect
dynamic channels resulting in the following trace:

< ACL Data TX: Handle 3585 flags 0x00 dlen 12
      LE L2CAP: Disconnection Request (0x06) ident 2 len 4
        Destination CID: 64
        Source CID: 64
> ACL Data RX: Handle 3585 flags 0x02 dlen 12
      LE L2CAP: Disconnection Response (0x07) ident 2 len 4
        Destination CID: 64
        Source CID: 64

Change-Id: I77ec29c8879a330b7f73e217621436045fa5163e
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Luiz Augusto von Dentz 2015-11-06 13:12:44 +02:00 committed by Anas Nashif
commit a983eff168
2 changed files with 74 additions and 0 deletions

View file

@ -118,6 +118,17 @@ int bt_l2cap_server_register(struct bt_l2cap_server *server);
int bt_l2cap_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan,
uint16_t psm);
/** @brief Disconnect L2CAP channel
*
* Disconnect L2CAP channel, if the connection is pending it will be
* canceled.
*
* @param chan Channel object.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan);
#endif /* CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL */
#endif /* CONFIG_BLUETOOTH_CENTRAL || CONFIG_BLUETOOTH_PERIPHERAL */
#endif /* __BT_L2CAP_H */

View file

@ -615,6 +615,32 @@ static void le_conn_rsp(struct bt_l2cap *l2cap, uint8_t ident,
l2cap_chan_del(chan);
}
}
static void le_disconn_rsp(struct bt_l2cap *l2cap, uint8_t ident,
struct net_buf *buf)
{
struct bt_conn *conn = l2cap->chan.conn;
struct bt_l2cap_chan *chan;
struct bt_l2cap_disconn_rsp *rsp = (void *)buf->data;
uint16_t dcid, scid;
if (buf->len < sizeof(*rsp)) {
BT_ERR("Too small LE disconn rsp packet size\n");
return;
}
dcid = sys_le16_to_cpu(rsp->dcid);
scid = sys_le16_to_cpu(rsp->scid);
BT_DBG("dcid 0x%04x scid 0x%04x\n", dcid, scid);
chan = l2cap_remove_tx_cid(conn, scid);
if (!chan) {
return;
}
l2cap_chan_del(chan);
}
#endif /* CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL */
static void l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
@ -663,6 +689,9 @@ static void l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
case BT_L2CAP_DISCONN_REQ:
le_disconn_req(l2cap, hdr->ident, buf);
break;
case BT_L2CAP_DISCONN_RSP:
le_disconn_rsp(l2cap, hdr->ident, buf);
break;
#endif /* CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL */
default:
BT_WARN("Unknown L2CAP PDU code 0x%02x\n", hdr->code);
@ -956,4 +985,38 @@ int bt_l2cap_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan,
/* TODO: Check conn/address type when BR/EDR is introduced */
return l2cap_le_connect(conn, chan, psm);
}
int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan)
{
struct bt_conn *conn = chan->conn;
struct net_buf *buf;
struct bt_l2cap_disconn_req *req;
struct bt_l2cap_sig_hdr *hdr;
BT_DBG("chan %p scid 0x%04x dcid 0x%04x\n", chan, chan->rx.cid,
chan->tx.cid);
if (!conn) {
return -ENOTCONN;
}
buf = bt_l2cap_create_pdu(&le_sig);
if (!buf) {
BT_ERR("Unable to send L2CP disconnect request\n");
return -ENOMEM;
}
hdr = net_buf_add(buf, sizeof(*hdr));
hdr->code = BT_L2CAP_DISCONN_REQ;
hdr->ident = get_ident(conn);
hdr->len = sys_cpu_to_le16(sizeof(*req));
req = net_buf_add(buf, sizeof(*req));
req->dcid = sys_cpu_to_le16(chan->tx.cid);
req->scid = sys_cpu_to_le16(chan->rx.cid);
bt_l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf);
return 0;
}
#endif /* CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL */