Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9c903e37 authored by David Herrmann's avatar David Herrmann Committed by Gustavo Padovan
Browse files

Bluetooth: l2cap: introduce l2cap_conn ref-counting



If we want to use l2cap_conn outside of l2cap_core.c, we need refcounting
for these objects. Otherwise, we cannot synchronize l2cap locks with
outside locks and end up with deadlocks.

Hence, introduce ref-counting for l2cap_conn objects. This doesn't affect
l2cap internals at all, as they use a direct synchronization.
We also keep a reference to the parent hci_conn for locking purposes as
l2cap_conn depends on this. This doesn't affect the connection itself but
only the lifetime of the (dead) object.

Signed-off-by: default avatarDavid Herrmann <dh.herrmann@gmail.com>
Acked-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarGustavo Padovan <gustavo.padovan@collabora.co.uk>
parent 3764eaa9
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -583,6 +583,7 @@ struct l2cap_conn {

	struct list_head	chan_l;
	struct mutex		chan_lock;
	struct kref		ref;
};

#define L2CAP_INFO_CL_MTU_REQ_SENT	0x01
@@ -813,4 +814,7 @@ void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
		       u8 status);
void __l2cap_physical_cfm(struct l2cap_chan *chan, int result);

void l2cap_conn_get(struct l2cap_conn *conn);
void l2cap_conn_put(struct l2cap_conn *conn);

#endif /* __L2CAP_H */
+24 −1
Original line number Diff line number Diff line
@@ -1486,7 +1486,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
	}

	hcon->l2cap_data = NULL;
	kfree(conn);
	conn->hchan = NULL;
	l2cap_conn_put(conn);
}

static void security_timeout(struct work_struct *work)
@@ -1520,8 +1521,10 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
		return NULL;
	}

	kref_init(&conn->ref);
	hcon->l2cap_data = conn;
	conn->hcon = hcon;
	hci_conn_get(conn->hcon);
	conn->hchan = hchan;

	BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
@@ -1558,6 +1561,26 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
	return conn;
}

static void l2cap_conn_free(struct kref *ref)
{
	struct l2cap_conn *conn = container_of(ref, struct l2cap_conn, ref);

	hci_conn_put(conn->hcon);
	kfree(conn);
}

void l2cap_conn_get(struct l2cap_conn *conn)
{
	kref_get(&conn->ref);
}
EXPORT_SYMBOL(l2cap_conn_get);

void l2cap_conn_put(struct l2cap_conn *conn)
{
	kref_put(&conn->ref, l2cap_conn_free);
}
EXPORT_SYMBOL(l2cap_conn_put);

/* ---- Socket interface ---- */

/* Find socket with psm and source / destination bdaddr.