aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/l2cap_core.c')
-rw-r--r--net/bluetooth/l2cap_core.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index be9ad89339cd..eae1d9f90b68 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1446,6 +1446,89 @@ static void l2cap_info_timeout(struct work_struct *work)
1446 l2cap_conn_start(conn); 1446 l2cap_conn_start(conn);
1447} 1447}
1448 1448
1449/*
1450 * l2cap_user
1451 * External modules can register l2cap_user objects on l2cap_conn. The ->probe
1452 * callback is called during registration. The ->remove callback is called
1453 * during unregistration.
1454 * An l2cap_user object can either be explicitly unregistered or when the
1455 * underlying l2cap_conn object is deleted. This guarantees that l2cap->hcon,
1456 * l2cap->hchan, .. are valid as long as the remove callback hasn't been called.
1457 * External modules must own a reference to the l2cap_conn object if they intend
1458 * to call l2cap_unregister_user(). The l2cap_conn object might get destroyed at
1459 * any time if they don't.
1460 */
1461
1462int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
1463{
1464 struct hci_dev *hdev = conn->hcon->hdev;
1465 int ret;
1466
1467 /* We need to check whether l2cap_conn is registered. If it is not, we
1468 * must not register the l2cap_user. l2cap_conn_del() is unregisters
1469 * l2cap_conn objects, but doesn't provide its own locking. Instead, it
1470 * relies on the parent hci_conn object to be locked. This itself relies
1471 * on the hci_dev object to be locked. So we must lock the hci device
1472 * here, too. */
1473
1474 hci_dev_lock(hdev);
1475
1476 if (user->list.next || user->list.prev) {
1477 ret = -EINVAL;
1478 goto out_unlock;
1479 }
1480
1481 /* conn->hchan is NULL after l2cap_conn_del() was called */
1482 if (!conn->hchan) {
1483 ret = -ENODEV;
1484 goto out_unlock;
1485 }
1486
1487 ret = user->probe(conn, user);
1488 if (ret)
1489 goto out_unlock;
1490
1491 list_add(&user->list, &conn->users);
1492 ret = 0;
1493
1494out_unlock:
1495 hci_dev_unlock(hdev);
1496 return ret;
1497}
1498EXPORT_SYMBOL(l2cap_register_user);
1499
1500void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
1501{
1502 struct hci_dev *hdev = conn->hcon->hdev;
1503
1504 hci_dev_lock(hdev);
1505
1506 if (!user->list.next || !user->list.prev)
1507 goto out_unlock;
1508
1509 list_del(&user->list);
1510 user->list.next = NULL;
1511 user->list.prev = NULL;
1512 user->remove(conn, user);
1513
1514out_unlock:
1515 hci_dev_unlock(hdev);
1516}
1517EXPORT_SYMBOL(l2cap_unregister_user);
1518
1519static void l2cap_unregister_all_users(struct l2cap_conn *conn)
1520{
1521 struct l2cap_user *user;
1522
1523 while (!list_empty(&conn->users)) {
1524 user = list_first_entry(&conn->users, struct l2cap_user, list);
1525 list_del(&user->list);
1526 user->list.next = NULL;
1527 user->list.prev = NULL;
1528 user->remove(conn, user);
1529 }
1530}
1531
1449static void l2cap_conn_del(struct hci_conn *hcon, int err) 1532static void l2cap_conn_del(struct hci_conn *hcon, int err)
1450{ 1533{
1451 struct l2cap_conn *conn = hcon->l2cap_data; 1534 struct l2cap_conn *conn = hcon->l2cap_data;
@@ -1458,6 +1541,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
1458 1541
1459 kfree_skb(conn->rx_skb); 1542 kfree_skb(conn->rx_skb);
1460 1543
1544 l2cap_unregister_all_users(conn);
1545
1461 mutex_lock(&conn->chan_lock); 1546 mutex_lock(&conn->chan_lock);
1462 1547
1463 /* Kill channels */ 1548 /* Kill channels */
@@ -1550,6 +1635,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
1550 mutex_init(&conn->chan_lock); 1635 mutex_init(&conn->chan_lock);
1551 1636
1552 INIT_LIST_HEAD(&conn->chan_l); 1637 INIT_LIST_HEAD(&conn->chan_l);
1638 INIT_LIST_HEAD(&conn->users);
1553 1639
1554 if (hcon->type == LE_LINK) 1640 if (hcon->type == LE_LINK)
1555 INIT_DELAYED_WORK(&conn->security_timer, security_timeout); 1641 INIT_DELAYED_WORK(&conn->security_timer, security_timeout);