net/bluetooth/l2cap_core.c

Source file repositories/reference/linux-study-clean/net/bluetooth/l2cap_core.c

File Facts

System
Linux kernel
Corpus path
net/bluetooth/l2cap_core.c
Extension
.c
Size
191370 bytes
Lines
7915
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

struct l2cap_ecred_conn_data {
	struct {
		struct l2cap_ecred_conn_req_hdr req;
		__le16 scid[5];
	} __packed pdu;
	struct l2cap_chan *chan;
	struct pid *pid;
	int count;
};

static void l2cap_ecred_defer_connect(struct l2cap_chan *chan, void *data)
{
	struct l2cap_ecred_conn_data *conn = data;
	struct pid *pid;

	if (chan == conn->chan)
		return;

	if (!test_and_clear_bit(FLAG_DEFER_SETUP, &chan->flags))
		return;

	pid = chan->ops->get_peer_pid(chan);

	/* Only add deferred channels with the same PID/PSM */
	if (conn->pid != pid || chan->psm != conn->chan->psm || chan->ident ||
	    chan->mode != L2CAP_MODE_EXT_FLOWCTL || chan->state != BT_CONNECT)
		return;

	if (test_and_set_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
		return;

	l2cap_ecred_init(chan, 0);

	/* Set the same ident so we can match on the rsp */
	chan->ident = conn->chan->ident;

	/* Include all channels deferred */
	conn->pdu.scid[conn->count] = cpu_to_le16(chan->scid);

	conn->count++;
}

static void l2cap_ecred_connect(struct l2cap_chan *chan)
{
	struct l2cap_conn *conn = chan->conn;
	struct l2cap_ecred_conn_data data;

	if (test_bit(FLAG_DEFER_SETUP, &chan->flags))
		return;

	if (test_and_set_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
		return;

	l2cap_ecred_init(chan, 0);

	memset(&data, 0, sizeof(data));
	data.pdu.req.psm     = chan->psm;
	data.pdu.req.mtu     = cpu_to_le16(chan->imtu);
	data.pdu.req.mps     = cpu_to_le16(chan->mps);
	data.pdu.req.credits = cpu_to_le16(chan->rx_credits);
	data.pdu.scid[0]     = cpu_to_le16(chan->scid);

	chan->ident = l2cap_get_ident(conn);

	data.count = 1;
	data.chan = chan;
	data.pid = chan->ops->get_peer_pid(chan);

	__l2cap_chan_list(conn, l2cap_ecred_defer_connect, &data);

	l2cap_send_cmd(conn, chan->ident, L2CAP_ECRED_CONN_REQ,
		       sizeof(data.pdu.req) + data.count * sizeof(__le16),
		       &data.pdu);
}

static void l2cap_le_start(struct l2cap_chan *chan)
{
	struct l2cap_conn *conn = chan->conn;

	if (!smp_conn_security(conn->hcon, chan->sec_level))
		return;

	if (!chan->psm) {
		l2cap_chan_ready(chan);
		return;
	}

	if (chan->state == BT_CONNECT) {
		if (chan->mode == L2CAP_MODE_EXT_FLOWCTL)
			l2cap_ecred_connect(chan);

Annotation

Implementation Notes