diff options
-rw-r--r-- | include/net/bluetooth/l2cap.h | 10 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 86 |
2 files changed, 96 insertions, 0 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 7b4cc5b98535..fb94cf13c777 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h | |||
@@ -584,6 +584,13 @@ struct l2cap_conn { | |||
584 | struct list_head chan_l; | 584 | struct list_head chan_l; |
585 | struct mutex chan_lock; | 585 | struct mutex chan_lock; |
586 | struct kref ref; | 586 | struct kref ref; |
587 | struct list_head users; | ||
588 | }; | ||
589 | |||
590 | struct l2cap_user { | ||
591 | struct list_head list; | ||
592 | int (*probe) (struct l2cap_conn *conn, struct l2cap_user *user); | ||
593 | void (*remove) (struct l2cap_conn *conn, struct l2cap_user *user); | ||
587 | }; | 594 | }; |
588 | 595 | ||
589 | #define L2CAP_INFO_CL_MTU_REQ_SENT 0x01 | 596 | #define L2CAP_INFO_CL_MTU_REQ_SENT 0x01 |
@@ -817,4 +824,7 @@ void __l2cap_physical_cfm(struct l2cap_chan *chan, int result); | |||
817 | void l2cap_conn_get(struct l2cap_conn *conn); | 824 | void l2cap_conn_get(struct l2cap_conn *conn); |
818 | void l2cap_conn_put(struct l2cap_conn *conn); | 825 | void l2cap_conn_put(struct l2cap_conn *conn); |
819 | 826 | ||
827 | int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user); | ||
828 | void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user); | ||
829 | |||
820 | #endif /* __L2CAP_H */ | 830 | #endif /* __L2CAP_H */ |
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 | |||
1462 | int 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 | |||
1494 | out_unlock: | ||
1495 | hci_dev_unlock(hdev); | ||
1496 | return ret; | ||
1497 | } | ||
1498 | EXPORT_SYMBOL(l2cap_register_user); | ||
1499 | |||
1500 | void 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 | |||
1514 | out_unlock: | ||
1515 | hci_dev_unlock(hdev); | ||
1516 | } | ||
1517 | EXPORT_SYMBOL(l2cap_unregister_user); | ||
1518 | |||
1519 | static 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 | |||
1449 | static void l2cap_conn_del(struct hci_conn *hcon, int err) | 1532 | static 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); |