xref: /haiku/src/add-ons/kernel/network/protocols/l2cap/L2capEndpointManager.cpp (revision 47c05920fde47c2618efccd24bd82f1e79cdf05a)
1 /*
2  * Copyright 2024, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 #include "L2capEndpointManager.h"
6 
7 #include <AutoDeleter.h>
8 
9 #include <bluetooth/bdaddrUtils.h>
10 
11 
12 L2capEndpointManager gL2capEndpointManager;
13 
14 
15 L2capEndpointManager::L2capEndpointManager()
16 	:
17 	fNextChannelID(L2CAP_FIRST_CID)
18 {
19 	rw_lock_init(&fBoundEndpointsLock, "l2cap bound endpoints");
20 	rw_lock_init(&fChannelEndpointsLock, "l2cap channel endpoints");
21 }
22 
23 
24 L2capEndpointManager::~L2capEndpointManager()
25 {
26 	rw_lock_destroy(&fBoundEndpointsLock);
27 	rw_lock_destroy(&fChannelEndpointsLock);
28 }
29 
30 
31 status_t
32 L2capEndpointManager::Bind(L2capEndpoint* endpoint, const sockaddr_l2cap& address)
33 {
34 	// TODO: Support binding to specific addresses?
35 	if (!Bluetooth::bdaddrUtils::Compare(address.l2cap_bdaddr, BDADDR_ANY))
36 		return EINVAL;
37 
38 	// PSM values must be odd.
39 	if ((address.l2cap_psm & 1) == 0)
40 		return EINVAL;
41 
42 	WriteLocker _(fBoundEndpointsLock);
43 
44 	if (fBoundEndpoints.Find(address.l2cap_psm) != NULL)
45 		return EADDRINUSE;
46 
47 	memcpy(*endpoint->LocalAddress(), &address, sizeof(struct sockaddr_l2cap));
48 	fBoundEndpoints.Insert(endpoint);
49 	gSocketModule->acquire_socket(endpoint->socket);
50 
51 	return B_OK;
52 }
53 
54 
55 status_t
56 L2capEndpointManager::Unbind(L2capEndpoint* endpoint)
57 {
58 	WriteLocker _(fBoundEndpointsLock);
59 
60 	fBoundEndpoints.Remove(endpoint);
61 	(*endpoint->LocalAddress())->sa_len = 0;
62 	gSocketModule->release_socket(endpoint->socket);
63 
64 	return B_OK;
65 }
66 
67 
68 L2capEndpoint*
69 L2capEndpointManager::ForPSM(uint16 psm)
70 {
71 	ReadLocker _(fBoundEndpointsLock);
72 	// TODO: Acquire reference?
73 	return fBoundEndpoints.Find(psm);
74 }
75 
76 
77 status_t
78 L2capEndpointManager::BindToChannel(L2capEndpoint* endpoint)
79 {
80 	WriteLocker _(fChannelEndpointsLock);
81 
82 	for (uint16 i = 0; i < (L2CAP_LAST_CID - L2CAP_FIRST_CID); i++) {
83 		const uint16 cid = fNextChannelID;
84 		fNextChannelID++;
85 		if (fNextChannelID < L2CAP_FIRST_CID)
86 			fNextChannelID = L2CAP_FIRST_CID;
87 
88 		if (fChannelEndpoints.Find(cid) != NULL)
89 			continue;
90 
91 		endpoint->fChannelID = cid;
92 		fChannelEndpoints.Insert(endpoint);
93 		gSocketModule->acquire_socket(endpoint->socket);
94 		return B_OK;
95 	}
96 
97 	return EADDRINUSE;
98 }
99 
100 
101 status_t
102 L2capEndpointManager::UnbindFromChannel(L2capEndpoint* endpoint)
103 {
104 	WriteLocker _(fChannelEndpointsLock);
105 
106 	fChannelEndpoints.Remove(endpoint);
107 	endpoint->fChannelID = 0;
108 	gSocketModule->release_socket(endpoint->socket);
109 
110 	return B_OK;
111 }
112 
113 
114 L2capEndpoint*
115 L2capEndpointManager::ForChannel(uint16 cid)
116 {
117 	ReadLocker _(fChannelEndpointsLock);
118 	// TODO: Acquire reference?
119 	return fChannelEndpoints.Find(cid);
120 }
121 
122 
123 void
124 L2capEndpointManager::Disconnected(HciConnection* connection)
125 {
126 	ReadLocker _(fChannelEndpointsLock);
127 	auto iter = fChannelEndpoints.GetIterator();
128 	while (iter.HasNext()) {
129 		L2capEndpoint* endpoint = iter.Next();
130 		if (endpoint->fConnection != connection)
131 			continue;
132 
133 		endpoint->fConnection = NULL;
134 		endpoint->fState = L2capEndpoint::CLOSED;
135 	}
136 }
137 
138