xref: /haiku/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.cpp (revision 91e6e52158a16f953a8919beac0dc9d9e07e285a)
1a94c1dc5SOliver Ruiz Dorantes /*
2bb83316aSAugustin Cavalier  * Copyright 2008, Oliver Ruiz Dorantes. All rights reserved.
3bb83316aSAugustin Cavalier  * Copyright 2024, Haiku, Inc. All rights reserved.
4bb83316aSAugustin Cavalier  * Distributed under the terms of the MIT License.
5a94c1dc5SOliver Ruiz Dorantes  */
6b9b8d43cSOliver Ruiz Dorantes #include "L2capEndpoint.h"
7b9b8d43cSOliver Ruiz Dorantes 
8b9b8d43cSOliver Ruiz Dorantes #include <stdio.h>
9b9b8d43cSOliver Ruiz Dorantes #include <string.h>
10b9b8d43cSOliver Ruiz Dorantes 
11bb83316aSAugustin Cavalier #include <NetBufferUtilities.h>
12a5bf1237SOliver Ruiz Dorantes 
13b9b8d43cSOliver Ruiz Dorantes #include <btDebug.h>
14bb83316aSAugustin Cavalier #include "L2capEndpointManager.h"
15bb83316aSAugustin Cavalier #include "l2cap_address.h"
16bb83316aSAugustin Cavalier #include "l2cap_signal.h"
17bb83316aSAugustin Cavalier 
18bb83316aSAugustin Cavalier 
19bb83316aSAugustin Cavalier static l2cap_qos sDefaultQOS = {
20bb83316aSAugustin Cavalier 	.flags = 0x0,
21bb83316aSAugustin Cavalier 	.service_type = 1,
22bb83316aSAugustin Cavalier 	.token_rate = 0xffffffff, /* maximum */
23bb83316aSAugustin Cavalier 	.token_bucket_size = 0xffffffff, /* maximum */
24bb83316aSAugustin Cavalier 	.peak_bandwidth = 0x00000000, /* maximum */
25bb83316aSAugustin Cavalier 	.access_latency = 0xffffffff, /* don't care */
26bb83316aSAugustin Cavalier 	.delay_variation = 0xffffffff /* don't care */
27bb83316aSAugustin Cavalier };
28b9b8d43cSOliver Ruiz Dorantes 
29a94c1dc5SOliver Ruiz Dorantes 
30b9b8d43cSOliver Ruiz Dorantes static inline bigtime_t
absolute_timeout(bigtime_t timeout)31b9b8d43cSOliver Ruiz Dorantes absolute_timeout(bigtime_t timeout)
32b9b8d43cSOliver Ruiz Dorantes {
33b9b8d43cSOliver Ruiz Dorantes 	if (timeout == 0 || timeout == B_INFINITE_TIMEOUT)
34b9b8d43cSOliver Ruiz Dorantes 		return timeout;
35b9b8d43cSOliver Ruiz Dorantes 
36b9b8d43cSOliver Ruiz Dorantes 	return timeout + system_time();
37b9b8d43cSOliver Ruiz Dorantes }
38b9b8d43cSOliver Ruiz Dorantes 
39b9b8d43cSOliver Ruiz Dorantes 
40bb83316aSAugustin Cavalier static inline status_t
posix_error(status_t error)41bb83316aSAugustin Cavalier posix_error(status_t error)
42bb83316aSAugustin Cavalier {
43bb83316aSAugustin Cavalier 	if (error == B_TIMED_OUT)
44bb83316aSAugustin Cavalier 		return B_WOULD_BLOCK;
45bb83316aSAugustin Cavalier 
46bb83316aSAugustin Cavalier 	return error;
47bb83316aSAugustin Cavalier }
48bb83316aSAugustin Cavalier 
49bb83316aSAugustin Cavalier 
50bb83316aSAugustin Cavalier // #pragma mark - endpoint
51bb83316aSAugustin Cavalier 
52bb83316aSAugustin Cavalier 
L2capEndpoint(net_socket * socket)53b9b8d43cSOliver Ruiz Dorantes L2capEndpoint::L2capEndpoint(net_socket* socket)
54b9b8d43cSOliver Ruiz Dorantes 	:
55b9b8d43cSOliver Ruiz Dorantes 	ProtocolSocket(socket),
56bb83316aSAugustin Cavalier 	fAcceptSemaphore(-1),
57bb83316aSAugustin Cavalier 	fState(CLOSED),
58bb83316aSAugustin Cavalier 	fConnection(NULL),
59bb83316aSAugustin Cavalier 	fChannelID(L2CAP_NULL_CID),
60bb83316aSAugustin Cavalier 	fDestinationChannelID(L2CAP_NULL_CID)
61b9b8d43cSOliver Ruiz Dorantes {
62c58e1d7fSAlexander von Gluck IV 	CALLED();
63b9b8d43cSOliver Ruiz Dorantes 
64bb83316aSAugustin Cavalier 	mutex_init(&fLock, "l2cap endpoint");
65bb83316aSAugustin Cavalier 	fCommandWait.Init(this, "l2cap endpoint command");
66b9b8d43cSOliver Ruiz Dorantes 
67bb83316aSAugustin Cavalier 	// Set MTU and flow control settings to defaults
68bb83316aSAugustin Cavalier 	fChannelConfig.incoming_mtu = L2CAP_MTU_DEFAULT;
69bb83316aSAugustin Cavalier 	memcpy(&fChannelConfig.incoming_flow, &sDefaultQOS, sizeof(l2cap_qos));
707cc7cadaSOliver Ruiz Dorantes 
71bb83316aSAugustin Cavalier 	fChannelConfig.outgoing_mtu = L2CAP_MTU_DEFAULT;
72bb83316aSAugustin Cavalier 	memcpy(&fChannelConfig.outgoing_flow, &sDefaultQOS, sizeof(l2cap_qos));
737cc7cadaSOliver Ruiz Dorantes 
74bb83316aSAugustin Cavalier 	fChannelConfig.flush_timeout = L2CAP_FLUSH_TIMEOUT_DEFAULT;
75bb83316aSAugustin Cavalier 	fChannelConfig.link_timeout  = L2CAP_LINK_TIMEOUT_DEFAULT;
76bb83316aSAugustin Cavalier 
77bb83316aSAugustin Cavalier 	fConfigState = {};
78bb83316aSAugustin Cavalier 
79bb83316aSAugustin Cavalier 	gStackModule->init_fifo(&fReceiveQueue, "l2cap recv", L2CAP_MTU_MAXIMUM);
80bb83316aSAugustin Cavalier 	gStackModule->init_fifo(&fSendQueue, "l2cap send", L2CAP_MTU_MAXIMUM);
81bb83316aSAugustin Cavalier 	gStackModule->init_timer(&fSendTimer, L2capEndpoint::_SendTimer, this);
82b9b8d43cSOliver Ruiz Dorantes }
83b9b8d43cSOliver Ruiz Dorantes 
84b9b8d43cSOliver Ruiz Dorantes 
~L2capEndpoint()85b9b8d43cSOliver Ruiz Dorantes L2capEndpoint::~L2capEndpoint()
86b9b8d43cSOliver Ruiz Dorantes {
87c58e1d7fSAlexander von Gluck IV 	CALLED();
88b9b8d43cSOliver Ruiz Dorantes 
89bb83316aSAugustin Cavalier 	mutex_lock(&fLock);
90bb83316aSAugustin Cavalier 	mutex_destroy(&fLock);
91bb83316aSAugustin Cavalier 
92bb83316aSAugustin Cavalier 	ASSERT(fState == CLOSED);
93bb83316aSAugustin Cavalier 
94bb83316aSAugustin Cavalier 	fCommandWait.NotifyAll(B_ERROR);
95bb83316aSAugustin Cavalier 
96bb83316aSAugustin Cavalier 	gStackModule->uninit_fifo(&fReceiveQueue);
97bb83316aSAugustin Cavalier 	gStackModule->uninit_fifo(&fSendQueue);
98bb83316aSAugustin Cavalier 	gStackModule->wait_for_timer(&fSendTimer);
99b9b8d43cSOliver Ruiz Dorantes }
100b9b8d43cSOliver Ruiz Dorantes 
101b9b8d43cSOliver Ruiz Dorantes 
102b9b8d43cSOliver Ruiz Dorantes status_t
_WaitForStateChange(bigtime_t absoluteTimeout)103bb83316aSAugustin Cavalier L2capEndpoint::_WaitForStateChange(bigtime_t absoluteTimeout)
104b9b8d43cSOliver Ruiz Dorantes {
105bb83316aSAugustin Cavalier 	channel_status state = fState;
106bb83316aSAugustin Cavalier 	while (fState == state) {
107bb83316aSAugustin Cavalier 		status_t status = fCommandWait.Wait(&fLock,
108bb83316aSAugustin Cavalier 			B_ABSOLUTE_TIMEOUT | B_CAN_INTERRUPT, absoluteTimeout);
109bb83316aSAugustin Cavalier 		if (status != B_OK)
110bb83316aSAugustin Cavalier 			return posix_error(status);
111b9b8d43cSOliver Ruiz Dorantes 	}
112b9b8d43cSOliver Ruiz Dorantes 
113bb83316aSAugustin Cavalier 	return B_OK;
114b9b8d43cSOliver Ruiz Dorantes }
115b9b8d43cSOliver Ruiz Dorantes 
116b9b8d43cSOliver Ruiz Dorantes 
117b9b8d43cSOliver Ruiz Dorantes status_t
Open()118b9b8d43cSOliver Ruiz Dorantes L2capEndpoint::Open()
119b9b8d43cSOliver Ruiz Dorantes {
120c58e1d7fSAlexander von Gluck IV 	CALLED();
121bb83316aSAugustin Cavalier 	return ProtocolSocket::Open();
122bb83316aSAugustin Cavalier }
123b9b8d43cSOliver Ruiz Dorantes 
124bb83316aSAugustin Cavalier 
125bb83316aSAugustin Cavalier status_t
Shutdown()126bb83316aSAugustin Cavalier L2capEndpoint::Shutdown()
127bb83316aSAugustin Cavalier {
128bb83316aSAugustin Cavalier 	CALLED();
129bb83316aSAugustin Cavalier 	MutexLocker locker(fLock);
130bb83316aSAugustin Cavalier 
131bb83316aSAugustin Cavalier 	if (fState == CLOSED) {
132bb83316aSAugustin Cavalier 		// Nothing to do.
133bb83316aSAugustin Cavalier 		return B_OK;
134bb83316aSAugustin Cavalier 	}
135bb83316aSAugustin Cavalier 	if (fState == LISTEN) {
136bb83316aSAugustin Cavalier 		delete_sem(fAcceptSemaphore);
137bb83316aSAugustin Cavalier 		fAcceptSemaphore = -1;
138bb83316aSAugustin Cavalier 		gSocketModule->set_max_backlog(socket, 0);
139bb83316aSAugustin Cavalier 		fState = BOUND;
140bb83316aSAugustin Cavalier 		return B_OK;
141bb83316aSAugustin Cavalier 	}
142bb83316aSAugustin Cavalier 
143bb83316aSAugustin Cavalier 	status_t status;
144bb83316aSAugustin Cavalier 	bigtime_t timeout = absolute_timeout(socket->receive.timeout);
145bb83316aSAugustin Cavalier 	if (gStackModule->is_restarted_syscall())
146bb83316aSAugustin Cavalier 		timeout = gStackModule->restore_syscall_restart_timeout();
147bb83316aSAugustin Cavalier 	else
148bb83316aSAugustin Cavalier 		gStackModule->store_syscall_restart_timeout(timeout);
149bb83316aSAugustin Cavalier 
150bb83316aSAugustin Cavalier 	// FIXME: If we are currently waiting for a connection or configuration,
151bb83316aSAugustin Cavalier 	// we need to wait for that command to return (and free its ident on timeout.)
152bb83316aSAugustin Cavalier 
153bb83316aSAugustin Cavalier 	while (fState > OPEN) {
154bb83316aSAugustin Cavalier 		status = _WaitForStateChange(timeout);
155bb83316aSAugustin Cavalier 		if (status != B_OK)
156bb83316aSAugustin Cavalier 			return status;
157bb83316aSAugustin Cavalier 	}
158bb83316aSAugustin Cavalier 	if (fState == CLOSED)
159bb83316aSAugustin Cavalier 		return B_OK;
160bb83316aSAugustin Cavalier 
161bb83316aSAugustin Cavalier 	uint8 ident = btCoreData->allocate_command_ident(fConnection, this);
162bb83316aSAugustin Cavalier 	if (ident == L2CAP_NULL_IDENT)
163bb83316aSAugustin Cavalier 		return ENOBUFS;
164bb83316aSAugustin Cavalier 
165bb83316aSAugustin Cavalier 	status = send_l2cap_disconnection_req(fConnection, ident,
166bb83316aSAugustin Cavalier 		fDestinationChannelID, fChannelID);
167bb83316aSAugustin Cavalier 	if (status != B_OK)
168bb83316aSAugustin Cavalier 		return status;
169bb83316aSAugustin Cavalier 
170bb83316aSAugustin Cavalier 	fState = WAIT_FOR_DISCONNECTION_RSP;
171bb83316aSAugustin Cavalier 
172bb83316aSAugustin Cavalier 	while (fState != CLOSED) {
173bb83316aSAugustin Cavalier 		status = _WaitForStateChange(timeout);
174bb83316aSAugustin Cavalier 		if (status != B_OK)
175bb83316aSAugustin Cavalier 			return status;
176bb83316aSAugustin Cavalier 	}
177b9b8d43cSOliver Ruiz Dorantes 
178a94c1dc5SOliver Ruiz Dorantes 	return B_OK;
179b9b8d43cSOliver Ruiz Dorantes }
180b9b8d43cSOliver Ruiz Dorantes 
181b9b8d43cSOliver Ruiz Dorantes 
182b9b8d43cSOliver Ruiz Dorantes status_t
Close()183b9b8d43cSOliver Ruiz Dorantes L2capEndpoint::Close()
184b9b8d43cSOliver Ruiz Dorantes {
185bb83316aSAugustin Cavalier 	return Shutdown();
186b9b8d43cSOliver Ruiz Dorantes }
187b9b8d43cSOliver Ruiz Dorantes 
188b9b8d43cSOliver Ruiz Dorantes 
189b9b8d43cSOliver Ruiz Dorantes status_t
Free()190b9b8d43cSOliver Ruiz Dorantes L2capEndpoint::Free()
191b9b8d43cSOliver Ruiz Dorantes {
192c58e1d7fSAlexander von Gluck IV 	CALLED();
193b9b8d43cSOliver Ruiz Dorantes 
194a94c1dc5SOliver Ruiz Dorantes 	return B_OK;
195b9b8d43cSOliver Ruiz Dorantes }
196b9b8d43cSOliver Ruiz Dorantes 
197b9b8d43cSOliver Ruiz Dorantes 
198b9b8d43cSOliver Ruiz Dorantes status_t
Bind(const struct sockaddr * _address)199b9b8d43cSOliver Ruiz Dorantes L2capEndpoint::Bind(const struct sockaddr* _address)
200b9b8d43cSOliver Ruiz Dorantes {
201a5bf1237SOliver Ruiz Dorantes 	const sockaddr_l2cap* address
202a5bf1237SOliver Ruiz Dorantes 		= reinterpret_cast<const sockaddr_l2cap*>(_address);
203bb83316aSAugustin Cavalier 	if (AddressModule()->is_empty_address(_address, true))
204bb83316aSAugustin Cavalier 		return B_OK; // We don't need to bind to empty.
205bb83316aSAugustin Cavalier 	if (!AddressModule()->is_same_family(_address))
206a94c1dc5SOliver Ruiz Dorantes 		return EAFNOSUPPORT;
207a5bf1237SOliver Ruiz Dorantes 	if (address->l2cap_len != sizeof(struct sockaddr_l2cap))
208a5bf1237SOliver Ruiz Dorantes 		return EAFNOSUPPORT;
209b9b8d43cSOliver Ruiz Dorantes 
210bb83316aSAugustin Cavalier 	CALLED();
211bb83316aSAugustin Cavalier 	MutexLocker _(fLock);
212b9b8d43cSOliver Ruiz Dorantes 
213bb83316aSAugustin Cavalier 	if (fState != CLOSED)
214bb83316aSAugustin Cavalier 		return EISCONN;
215b9b8d43cSOliver Ruiz Dorantes 
216bb83316aSAugustin Cavalier 	status_t status = gL2capEndpointManager.Bind(this, *address);
217bb83316aSAugustin Cavalier 	if (status != B_OK)
218bb83316aSAugustin Cavalier 		return status;
219b9b8d43cSOliver Ruiz Dorantes 
22031f87630SOliver Ruiz Dorantes 	fState = BOUND;
221b9b8d43cSOliver Ruiz Dorantes 	return B_OK;
222b9b8d43cSOliver Ruiz Dorantes }
223b9b8d43cSOliver Ruiz Dorantes 
224b9b8d43cSOliver Ruiz Dorantes 
225b9b8d43cSOliver Ruiz Dorantes status_t
Unbind()226b9b8d43cSOliver Ruiz Dorantes L2capEndpoint::Unbind()
227b9b8d43cSOliver Ruiz Dorantes {
228c58e1d7fSAlexander von Gluck IV 	CALLED();
229bb83316aSAugustin Cavalier 	MutexLocker _(fLock);
230b9b8d43cSOliver Ruiz Dorantes 
231bb83316aSAugustin Cavalier 	if (LocalAddress().IsEmpty(true))
232bb83316aSAugustin Cavalier 		return EINVAL;
233bb83316aSAugustin Cavalier 
234bb83316aSAugustin Cavalier 	status_t status = gL2capEndpointManager.Unbind(this);
235bb83316aSAugustin Cavalier 	if (status != B_OK)
236bb83316aSAugustin Cavalier 		return status;
237bb83316aSAugustin Cavalier 
238bb83316aSAugustin Cavalier 	if (fState == BOUND)
239bb83316aSAugustin Cavalier 		fState = CLOSED;
240a94c1dc5SOliver Ruiz Dorantes 	return B_OK;
241b9b8d43cSOliver Ruiz Dorantes }
242b9b8d43cSOliver Ruiz Dorantes 
243b9b8d43cSOliver Ruiz Dorantes 
244b9b8d43cSOliver Ruiz Dorantes status_t
Listen(int backlog)245b9b8d43cSOliver Ruiz Dorantes L2capEndpoint::Listen(int backlog)
246b9b8d43cSOliver Ruiz Dorantes {
247c58e1d7fSAlexander von Gluck IV 	CALLED();
248bb83316aSAugustin Cavalier 	MutexLocker _(fLock);
249b9b8d43cSOliver Ruiz Dorantes 
250bb83316aSAugustin Cavalier 	if (fState != BOUND)
251a58b3b32SOliver Ruiz Dorantes 		return B_BAD_VALUE;
252a58b3b32SOliver Ruiz Dorantes 
253bb83316aSAugustin Cavalier 	fAcceptSemaphore = create_sem(0, "l2cap accept");
254bb83316aSAugustin Cavalier 	if (fAcceptSemaphore < B_OK) {
255c58e1d7fSAlexander von Gluck IV 		ERROR("%s: Semaphore could not be created\n", __func__);
256b9b8d43cSOliver Ruiz Dorantes 		return ENOBUFS;
257a58b3b32SOliver Ruiz Dorantes 	}
258a58b3b32SOliver Ruiz Dorantes 
259a58b3b32SOliver Ruiz Dorantes 	gSocketModule->set_max_backlog(socket, backlog);
260b9b8d43cSOliver Ruiz Dorantes 
261b9b8d43cSOliver Ruiz Dorantes 	fState = LISTEN;
262b9b8d43cSOliver Ruiz Dorantes 	return B_OK;
263b9b8d43cSOliver Ruiz Dorantes }
264b9b8d43cSOliver Ruiz Dorantes 
265b9b8d43cSOliver Ruiz Dorantes 
266b9b8d43cSOliver Ruiz Dorantes status_t
Connect(const struct sockaddr * _address)267b9b8d43cSOliver Ruiz Dorantes L2capEndpoint::Connect(const struct sockaddr* _address)
268b9b8d43cSOliver Ruiz Dorantes {
269a5bf1237SOliver Ruiz Dorantes 	const sockaddr_l2cap* address
270a5bf1237SOliver Ruiz Dorantes 		= reinterpret_cast<const sockaddr_l2cap*>(_address);
271bb83316aSAugustin Cavalier 	if (!AddressModule()->is_same_family(_address))
272bb83316aSAugustin Cavalier 		return EAFNOSUPPORT;
273bb83316aSAugustin Cavalier 	if (address->l2cap_len != sizeof(struct sockaddr_l2cap))
274bb83316aSAugustin Cavalier 		return EAFNOSUPPORT;
275b9b8d43cSOliver Ruiz Dorantes 
276bb83316aSAugustin Cavalier 	TRACE("l2cap: connect(\"%s\")\n",
277bb83316aSAugustin Cavalier 		ConstSocketAddress(&gL2capAddressModule, _address).AsString().Data());
278bb83316aSAugustin Cavalier 	MutexLocker _(fLock);
279b9b8d43cSOliver Ruiz Dorantes 
280bb83316aSAugustin Cavalier 	status_t status;
281bb83316aSAugustin Cavalier 	bigtime_t timeout = absolute_timeout(socket->send.timeout);
282bb83316aSAugustin Cavalier 	if (gStackModule->is_restarted_syscall()) {
283bb83316aSAugustin Cavalier 		timeout = gStackModule->restore_syscall_restart_timeout();
284b9b8d43cSOliver Ruiz Dorantes 
285bb83316aSAugustin Cavalier 		while (fState != CLOSED && fState != OPEN) {
286bb83316aSAugustin Cavalier 			status = _WaitForStateChange(timeout);
287bb83316aSAugustin Cavalier 			if (status != B_OK)
288bb83316aSAugustin Cavalier 				return status;
289ef36d964SOliver Ruiz Dorantes 		}
290bb83316aSAugustin Cavalier 		return (fState == OPEN) ? B_OK : ECONNREFUSED;
291a5bf1237SOliver Ruiz Dorantes 	} else {
292bb83316aSAugustin Cavalier 		gStackModule->store_syscall_restart_timeout(timeout);
293a5bf1237SOliver Ruiz Dorantes 	}
294a5bf1237SOliver Ruiz Dorantes 
295bb83316aSAugustin Cavalier 	if (fState == LISTEN)
296bb83316aSAugustin Cavalier 		return EINVAL;
297bb83316aSAugustin Cavalier 	if (fState == OPEN)
298bb83316aSAugustin Cavalier 		return EISCONN;
299bb83316aSAugustin Cavalier 	if (fState != CLOSED)
300bb83316aSAugustin Cavalier 		return EALREADY;
301bb83316aSAugustin Cavalier 
302bb83316aSAugustin Cavalier 	// Set up route.
303bb83316aSAugustin Cavalier 	hci_id hid = btCoreData->RouteConnection(address->l2cap_bdaddr);
304bb83316aSAugustin Cavalier 	if (hid <= 0)
305a5bf1237SOliver Ruiz Dorantes 		return ENETUNREACH;
306bb83316aSAugustin Cavalier 
307bb83316aSAugustin Cavalier 	TRACE("l2cap: %" B_PRId32 " for route %s\n", hid,
308bb83316aSAugustin Cavalier 		bdaddrUtils::ToString(address->l2cap_bdaddr).String());
309bb83316aSAugustin Cavalier 
310bb83316aSAugustin Cavalier 	fConnection = btCoreData->ConnectionByDestination(
311bb83316aSAugustin Cavalier 		address->l2cap_bdaddr, hid);
312bb83316aSAugustin Cavalier 	if (fConnection == NULL)
313bb83316aSAugustin Cavalier 		return EHOSTUNREACH;
314bb83316aSAugustin Cavalier 
315bb83316aSAugustin Cavalier 	memcpy(&socket->peer, _address, sizeof(struct sockaddr_l2cap));
316bb83316aSAugustin Cavalier 
317bb83316aSAugustin Cavalier 	status = gL2capEndpointManager.BindToChannel(this);
318bb83316aSAugustin Cavalier 	if (status != B_OK)
319bb83316aSAugustin Cavalier 		return status;
320bb83316aSAugustin Cavalier 
321bb83316aSAugustin Cavalier 	fConfigState = {};
322bb83316aSAugustin Cavalier 
323bb83316aSAugustin Cavalier 	uint8 ident = btCoreData->allocate_command_ident(fConnection, this);
324bb83316aSAugustin Cavalier 	if (ident == L2CAP_NULL_IDENT)
325bb83316aSAugustin Cavalier 		return ENOBUFS;
326bb83316aSAugustin Cavalier 
327bb83316aSAugustin Cavalier 	status = send_l2cap_connection_req(fConnection, ident,
328bb83316aSAugustin Cavalier 		address->l2cap_psm, fChannelID);
329bb83316aSAugustin Cavalier 	if (status != B_OK)
330bb83316aSAugustin Cavalier 		return status;
331bb83316aSAugustin Cavalier 
332bb83316aSAugustin Cavalier 	fState = WAIT_FOR_CONNECTION_RSP;
333bb83316aSAugustin Cavalier 
334bb83316aSAugustin Cavalier 	while (fState != CLOSED && fState != OPEN) {
335bb83316aSAugustin Cavalier 		status = _WaitForStateChange(timeout);
336bb83316aSAugustin Cavalier 		if (status != B_OK)
337bb83316aSAugustin Cavalier 			return status;
338bb83316aSAugustin Cavalier 	}
339bb83316aSAugustin Cavalier 	return (fState == OPEN) ? B_OK : ECONNREFUSED;
340b9b8d43cSOliver Ruiz Dorantes }
341b9b8d43cSOliver Ruiz Dorantes 
342b9b8d43cSOliver Ruiz Dorantes 
343b9b8d43cSOliver Ruiz Dorantes status_t
Accept(net_socket ** _acceptedSocket)344b9b8d43cSOliver Ruiz Dorantes L2capEndpoint::Accept(net_socket** _acceptedSocket)
345b9b8d43cSOliver Ruiz Dorantes {
346c58e1d7fSAlexander von Gluck IV 	CALLED();
347bb83316aSAugustin Cavalier 	MutexLocker locker(fLock);
348b9b8d43cSOliver Ruiz Dorantes 
349a58b3b32SOliver Ruiz Dorantes 	status_t status;
350bb83316aSAugustin Cavalier 	bigtime_t timeout = absolute_timeout(socket->receive.timeout);
351bb83316aSAugustin Cavalier 	if (gStackModule->is_restarted_syscall())
352bb83316aSAugustin Cavalier 		timeout = gStackModule->restore_syscall_restart_timeout();
353bb83316aSAugustin Cavalier 	else
354bb83316aSAugustin Cavalier 		gStackModule->store_syscall_restart_timeout(timeout);
355a58b3b32SOliver Ruiz Dorantes 
356a58b3b32SOliver Ruiz Dorantes 	do {
357bb83316aSAugustin Cavalier 		locker.Unlock();
358a58b3b32SOliver Ruiz Dorantes 
359bb83316aSAugustin Cavalier 		status = acquire_sem_etc(fAcceptSemaphore, 1, B_ABSOLUTE_TIMEOUT
360a58b3b32SOliver Ruiz Dorantes 			| B_CAN_INTERRUPT, timeout);
36131f87630SOliver Ruiz Dorantes 		if (status != B_OK) {
362bb83316aSAugustin Cavalier 			if (status == B_TIMED_OUT && socket->receive.timeout == 0)
363bb83316aSAugustin Cavalier 				return B_WOULD_BLOCK;
364a58b3b32SOliver Ruiz Dorantes 
365bb83316aSAugustin Cavalier 			return status;
36631f87630SOliver Ruiz Dorantes 		}
367a58b3b32SOliver Ruiz Dorantes 
368bb83316aSAugustin Cavalier 		locker.Lock();
369bb83316aSAugustin Cavalier 		status = gSocketModule->dequeue_connected(socket, _acceptedSocket);
370a58b3b32SOliver Ruiz Dorantes 	} while (status != B_OK);
371a58b3b32SOliver Ruiz Dorantes 
372a58b3b32SOliver Ruiz Dorantes 	return status;
373b9b8d43cSOliver Ruiz Dorantes }
374b9b8d43cSOliver Ruiz Dorantes 
375b9b8d43cSOliver Ruiz Dorantes 
376b9b8d43cSOliver Ruiz Dorantes ssize_t
ReadData(size_t numBytes,uint32 flags,net_buffer ** _buffer)3777cc7cadaSOliver Ruiz Dorantes L2capEndpoint::ReadData(size_t numBytes, uint32 flags, net_buffer** _buffer)
3787cc7cadaSOliver Ruiz Dorantes {
379c58e1d7fSAlexander von Gluck IV 	CALLED();
380bb83316aSAugustin Cavalier 	MutexLocker locker(fLock);
38131f87630SOliver Ruiz Dorantes 
382bb83316aSAugustin Cavalier 	*_buffer = NULL;
383bb83316aSAugustin Cavalier 
384bb83316aSAugustin Cavalier 	bigtime_t timeout = 0;
385bb83316aSAugustin Cavalier 	if ((flags & MSG_DONTWAIT) == 0) {
386bb83316aSAugustin Cavalier 		timeout = absolute_timeout(socket->receive.timeout);
387bb83316aSAugustin Cavalier 		if (gStackModule->is_restarted_syscall())
388bb83316aSAugustin Cavalier 			timeout = gStackModule->restore_syscall_restart_timeout();
389bb83316aSAugustin Cavalier 		else
390bb83316aSAugustin Cavalier 			gStackModule->store_syscall_restart_timeout(timeout);
39131f87630SOliver Ruiz Dorantes 	}
3927cc7cadaSOliver Ruiz Dorantes 
393bb83316aSAugustin Cavalier 	if (fState == CLOSED)
394bb83316aSAugustin Cavalier 		flags |= MSG_DONTWAIT;
395bb83316aSAugustin Cavalier 
396bb83316aSAugustin Cavalier 	return gStackModule->fifo_dequeue_buffer(&fReceiveQueue, flags, timeout, _buffer);
3977cc7cadaSOliver Ruiz Dorantes }
3987cc7cadaSOliver Ruiz Dorantes 
3997cc7cadaSOliver Ruiz Dorantes 
4007cc7cadaSOliver Ruiz Dorantes ssize_t
SendData(net_buffer * buffer)4018638173cSOliver Ruiz Dorantes L2capEndpoint::SendData(net_buffer* buffer)
4028638173cSOliver Ruiz Dorantes {
403c58e1d7fSAlexander von Gluck IV 	CALLED();
404bb83316aSAugustin Cavalier 	MutexLocker locker(fLock);
4058638173cSOliver Ruiz Dorantes 
406bb83316aSAugustin Cavalier 	if (buffer == NULL)
407bb83316aSAugustin Cavalier 		return ENOBUFS;
408bb83316aSAugustin Cavalier 
409bb83316aSAugustin Cavalier 	if (fState != OPEN)
410bb83316aSAugustin Cavalier 		return ENOTCONN;
411bb83316aSAugustin Cavalier 
412bb83316aSAugustin Cavalier 	ssize_t sent = 0;
413bb83316aSAugustin Cavalier 	while (buffer != NULL) {
414bb83316aSAugustin Cavalier 		net_buffer* current = buffer;
415bb83316aSAugustin Cavalier 		buffer = NULL;
416bb83316aSAugustin Cavalier 		if (current->size > fChannelConfig.outgoing_mtu) {
417bb83316aSAugustin Cavalier 			// Break up into MTU-sized chunks.
418bb83316aSAugustin Cavalier 			buffer = gBufferModule->split(current, fChannelConfig.outgoing_mtu);
419bb83316aSAugustin Cavalier 			if (buffer == NULL) {
420bb83316aSAugustin Cavalier 				if (sent > 0) {
421bb83316aSAugustin Cavalier 					gBufferModule->free(current);
422bb83316aSAugustin Cavalier 					return sent;
423bb83316aSAugustin Cavalier 				}
424bb83316aSAugustin Cavalier 				return ENOMEM;
425bb83316aSAugustin Cavalier 			}
4268638173cSOliver Ruiz Dorantes 		}
4278638173cSOliver Ruiz Dorantes 
428bb83316aSAugustin Cavalier 		const size_t bufferSize = current->size;
429bb83316aSAugustin Cavalier 		status_t status = gStackModule->fifo_enqueue_buffer(&fSendQueue, current);
430bb83316aSAugustin Cavalier 		if (status != B_OK) {
431bb83316aSAugustin Cavalier 			gBufferModule->free(current);
432bb83316aSAugustin Cavalier 			return sent;
433bb83316aSAugustin Cavalier 		}
4348638173cSOliver Ruiz Dorantes 
435bb83316aSAugustin Cavalier 		sent += bufferSize;
436bb83316aSAugustin Cavalier 	}
4378638173cSOliver Ruiz Dorantes 
438bb83316aSAugustin Cavalier 	if (!gStackModule->is_timer_active(&fSendTimer))
439bb83316aSAugustin Cavalier 		gStackModule->set_timer(&fSendTimer, 0);
440bb83316aSAugustin Cavalier 
441bb83316aSAugustin Cavalier 	return sent;
442bb83316aSAugustin Cavalier }
443bb83316aSAugustin Cavalier 
444bb83316aSAugustin Cavalier 
445bb83316aSAugustin Cavalier status_t
ReceiveData(net_buffer * buffer)446bb83316aSAugustin Cavalier L2capEndpoint::ReceiveData(net_buffer* buffer)
447bb83316aSAugustin Cavalier {
448bb83316aSAugustin Cavalier 	// FIXME: Check address specified in net_buffer!
449bb83316aSAugustin Cavalier 	return gStackModule->fifo_enqueue_buffer(&fReceiveQueue, buffer);
450bb83316aSAugustin Cavalier }
451bb83316aSAugustin Cavalier 
452bb83316aSAugustin Cavalier 
453bb83316aSAugustin Cavalier /*static*/ void
_SendTimer(net_timer * timer,void * _endpoint)454bb83316aSAugustin Cavalier L2capEndpoint::_SendTimer(net_timer* timer, void* _endpoint)
455bb83316aSAugustin Cavalier {
456bb83316aSAugustin Cavalier 	L2capEndpoint* endpoint = (L2capEndpoint*)_endpoint;
457bb83316aSAugustin Cavalier 
458bb83316aSAugustin Cavalier 	MutexLocker locker(endpoint->fLock);
459bb83316aSAugustin Cavalier 	if (!locker.IsLocked() || gStackModule->is_timer_active(timer))
460bb83316aSAugustin Cavalier 		return;
461bb83316aSAugustin Cavalier 
462bb83316aSAugustin Cavalier 	endpoint->_SendQueued();
463bb83316aSAugustin Cavalier }
464bb83316aSAugustin Cavalier 
465bb83316aSAugustin Cavalier 
466bb83316aSAugustin Cavalier void
_SendQueued()467bb83316aSAugustin Cavalier L2capEndpoint::_SendQueued()
468bb83316aSAugustin Cavalier {
469bb83316aSAugustin Cavalier 	CALLED();
470bb83316aSAugustin Cavalier 	ASSERT_LOCKED_MUTEX(&fLock);
471bb83316aSAugustin Cavalier 
472bb83316aSAugustin Cavalier 	if (fState != OPEN)
473bb83316aSAugustin Cavalier 		return;
474bb83316aSAugustin Cavalier 
475bb83316aSAugustin Cavalier 	net_buffer* buffer;
476bb83316aSAugustin Cavalier 	while (gStackModule->fifo_dequeue_buffer(&fSendQueue, MSG_DONTWAIT, 0, &buffer) >= 0) {
477bb83316aSAugustin Cavalier 		NetBufferPrepend<l2cap_basic_header> header(buffer);
478bb83316aSAugustin Cavalier 		if (header.Status() != B_OK) {
479bb83316aSAugustin Cavalier 			ERROR("%s: header could not be prepended!\n", __func__);
480bb83316aSAugustin Cavalier 			gBufferModule->free(buffer);
481bb83316aSAugustin Cavalier 			continue;
482bb83316aSAugustin Cavalier 		}
483bb83316aSAugustin Cavalier 
484bb83316aSAugustin Cavalier 		header->length = B_HOST_TO_LENDIAN_INT16(buffer->size - sizeof(l2cap_basic_header));
485bb83316aSAugustin Cavalier 		header->dcid = B_HOST_TO_LENDIAN_INT16(fDestinationChannelID);
486bb83316aSAugustin Cavalier 
487bb83316aSAugustin Cavalier 		buffer->type = fConnection->handle;
488bb83316aSAugustin Cavalier 		btDevices->PostACL(fConnection->ndevice->index, buffer);
489bb83316aSAugustin Cavalier 	}
4908638173cSOliver Ruiz Dorantes }
4918638173cSOliver Ruiz Dorantes 
4928638173cSOliver Ruiz Dorantes 
4938638173cSOliver Ruiz Dorantes ssize_t
Sendable()494b9b8d43cSOliver Ruiz Dorantes L2capEndpoint::Sendable()
495b9b8d43cSOliver Ruiz Dorantes {
496c58e1d7fSAlexander von Gluck IV 	CALLED();
497bb83316aSAugustin Cavalier 	MutexLocker locker(fLock);
498bb83316aSAugustin Cavalier 
499bb83316aSAugustin Cavalier 	if (fState != OPEN) {
500bb83316aSAugustin Cavalier 		if (_IsEstablishing())
501bb83316aSAugustin Cavalier 			return 0;
502bb83316aSAugustin Cavalier 		return EPIPE;
503bb83316aSAugustin Cavalier 	}
504bb83316aSAugustin Cavalier 
505bb83316aSAugustin Cavalier 	MutexLocker fifoLocker(fSendQueue.lock);
506bb83316aSAugustin Cavalier 	return (fSendQueue.max_bytes - fSendQueue.current_bytes);
507b9b8d43cSOliver Ruiz Dorantes }
508b9b8d43cSOliver Ruiz Dorantes 
509b9b8d43cSOliver Ruiz Dorantes 
510b9b8d43cSOliver Ruiz Dorantes ssize_t
Receivable()511b9b8d43cSOliver Ruiz Dorantes L2capEndpoint::Receivable()
512b9b8d43cSOliver Ruiz Dorantes {
513c58e1d7fSAlexander von Gluck IV 	CALLED();
514bb83316aSAugustin Cavalier 	MutexLocker locker(fLock);
515b9b8d43cSOliver Ruiz Dorantes 
516bb83316aSAugustin Cavalier 	MutexLocker fifoLocker(fReceiveQueue.lock);
517bb83316aSAugustin Cavalier 	return fReceiveQueue.current_bytes;
518b9b8d43cSOliver Ruiz Dorantes }
5197cc7cadaSOliver Ruiz Dorantes 
5207cc7cadaSOliver Ruiz Dorantes 
5217cc7cadaSOliver Ruiz Dorantes void
_HandleCommandRejected(uint8 ident,uint16 reason,const l2cap_command_reject_data & data)522bb83316aSAugustin Cavalier L2capEndpoint::_HandleCommandRejected(uint8 ident, uint16 reason,
523bb83316aSAugustin Cavalier 	const l2cap_command_reject_data& data)
5247cc7cadaSOliver Ruiz Dorantes {
525bb83316aSAugustin Cavalier 	CALLED();
526bb83316aSAugustin Cavalier 	MutexLocker locker(fLock);
527bb83316aSAugustin Cavalier 
528bb83316aSAugustin Cavalier 	switch (fState) {
529bb83316aSAugustin Cavalier 		case WAIT_FOR_CONNECTION_RSP:
530bb83316aSAugustin Cavalier 			// Connection request was rejected. Reset state.
531bb83316aSAugustin Cavalier 			fState = CLOSED;
532bb83316aSAugustin Cavalier 			socket->error = ECONNREFUSED;
533bb83316aSAugustin Cavalier 		break;
534bb83316aSAugustin Cavalier 
535bb83316aSAugustin Cavalier 		case CONFIGURATION:
536bb83316aSAugustin Cavalier 			// TODO: Adjust and resend configuration request.
537bb83316aSAugustin Cavalier 		break;
538bb83316aSAugustin Cavalier 
539bb83316aSAugustin Cavalier 	default:
540bb83316aSAugustin Cavalier 		ERROR("l2cap: unknown command unexpectedly rejected (ident %d)\n", ident);
541bb83316aSAugustin Cavalier 		break;
542bb83316aSAugustin Cavalier 	}
543bb83316aSAugustin Cavalier 
544bb83316aSAugustin Cavalier 	fCommandWait.NotifyAll();
545bb83316aSAugustin Cavalier }
546bb83316aSAugustin Cavalier 
547bb83316aSAugustin Cavalier 
548bb83316aSAugustin Cavalier void
_HandleConnectionReq(HciConnection * connection,uint8 ident,uint16 psm,uint16 scid)549bb83316aSAugustin Cavalier L2capEndpoint::_HandleConnectionReq(HciConnection* connection,
550bb83316aSAugustin Cavalier 	uint8 ident, uint16 psm, uint16 scid)
551bb83316aSAugustin Cavalier {
552bb83316aSAugustin Cavalier 	MutexLocker locker(fLock);
553bb83316aSAugustin Cavalier 	if (fState != LISTEN) {
554bb83316aSAugustin Cavalier 		send_l2cap_connection_rsp(connection, ident, 0, scid,
555bb83316aSAugustin Cavalier 			l2cap_connection_rsp::RESULT_PSM_NOT_SUPPORTED, 0);
556bb83316aSAugustin Cavalier 		return;
557bb83316aSAugustin Cavalier 	}
558bb83316aSAugustin Cavalier 	locker.Unlock();
559bb83316aSAugustin Cavalier 
56031f87630SOliver Ruiz Dorantes 	net_socket* newSocket;
561bb83316aSAugustin Cavalier 	status_t status = gSocketModule->spawn_pending_socket(socket, &newSocket);
562bb83316aSAugustin Cavalier 	if (status != B_OK) {
563bb83316aSAugustin Cavalier 		ERROR("l2cap: could not spawn child for endpoint: %s\n", strerror(status));
564bb83316aSAugustin Cavalier 		send_l2cap_connection_rsp(connection, ident, 0, scid,
565bb83316aSAugustin Cavalier 			l2cap_connection_rsp::RESULT_NO_RESOURCES, 0);
56631f87630SOliver Ruiz Dorantes 		return;
56731f87630SOliver Ruiz Dorantes 	}
5687cc7cadaSOliver Ruiz Dorantes 
56931f87630SOliver Ruiz Dorantes 	L2capEndpoint* endpoint = (L2capEndpoint*)newSocket->first_protocol;
570bb83316aSAugustin Cavalier 	MutexLocker newEndpointLocker(endpoint->fLock);
5717cc7cadaSOliver Ruiz Dorantes 
572bb83316aSAugustin Cavalier 	status = gL2capEndpointManager.BindToChannel(endpoint);
573bb83316aSAugustin Cavalier 	if (status != B_OK) {
574bb83316aSAugustin Cavalier 		ERROR("l2cap: could not allocate channel for endpoint: %s\n", strerror(status));
575bb83316aSAugustin Cavalier 		send_l2cap_connection_rsp(connection, ident, 0, scid,
576bb83316aSAugustin Cavalier 			l2cap_connection_rsp::RESULT_NO_RESOURCES, 0);
577bb83316aSAugustin Cavalier 		return;
578bb83316aSAugustin Cavalier 	}
57931f87630SOliver Ruiz Dorantes 
580bb83316aSAugustin Cavalier 	endpoint->fAcceptSemaphore = fAcceptSemaphore;
58131f87630SOliver Ruiz Dorantes 
582bb83316aSAugustin Cavalier 	endpoint->fConnection = connection;
583bb83316aSAugustin Cavalier 	endpoint->fState = CONFIGURATION;
58431f87630SOliver Ruiz Dorantes 
585bb83316aSAugustin Cavalier 	endpoint->fDestinationChannelID = scid;
58631f87630SOliver Ruiz Dorantes 
587bb83316aSAugustin Cavalier 	send_l2cap_connection_rsp(connection, ident, endpoint->fChannelID, scid,
588bb83316aSAugustin Cavalier 		l2cap_connection_rsp::RESULT_SUCCESS, 0);
589a58b3b32SOliver Ruiz Dorantes }
590a58b3b32SOliver Ruiz Dorantes 
591a58b3b32SOliver Ruiz Dorantes 
592ef36d964SOliver Ruiz Dorantes void
_HandleConnectionRsp(uint8 ident,const l2cap_connection_rsp & response)593bb83316aSAugustin Cavalier L2capEndpoint::_HandleConnectionRsp(uint8 ident, const l2cap_connection_rsp& response)
594ef36d964SOliver Ruiz Dorantes {
595bb83316aSAugustin Cavalier 	CALLED();
596bb83316aSAugustin Cavalier 	MutexLocker locker(fLock);
597bb83316aSAugustin Cavalier 	fCommandWait.NotifyAll();
598ef36d964SOliver Ruiz Dorantes 
599bb83316aSAugustin Cavalier 	if (fState != WAIT_FOR_CONNECTION_RSP) {
600bb83316aSAugustin Cavalier 		ERROR("l2cap: unexpected connection response, scid=%d, state=%d\n",
601bb83316aSAugustin Cavalier 			response.scid, fState);
602bb83316aSAugustin Cavalier 		send_l2cap_command_reject(fConnection, ident,
603bb83316aSAugustin Cavalier 			l2cap_command_reject::REJECTED_INVALID_CID, 0, response.scid, response.dcid);
604bb83316aSAugustin Cavalier 		return;
605bb83316aSAugustin Cavalier 	}
606ef36d964SOliver Ruiz Dorantes 
607bb83316aSAugustin Cavalier 	if (fChannelID != response.scid) {
608bb83316aSAugustin Cavalier 		ERROR("l2cap: invalid connection response, mismatched SCIDs (%d, %d)\n",
609bb83316aSAugustin Cavalier 			fChannelID, response.scid);
610bb83316aSAugustin Cavalier 		send_l2cap_command_reject(fConnection, ident,
611bb83316aSAugustin Cavalier 			l2cap_command_reject::REJECTED_INVALID_CID, 0, response.scid, response.dcid);
612bb83316aSAugustin Cavalier 		return;
613bb83316aSAugustin Cavalier 	}
614bb83316aSAugustin Cavalier 
615bb83316aSAugustin Cavalier 	if (response.result == l2cap_connection_rsp::RESULT_PENDING) {
616bb83316aSAugustin Cavalier 		// The connection is still pending on the remote end.
617bb83316aSAugustin Cavalier 		// We will receive another CONNECTION_RSP later.
618bb83316aSAugustin Cavalier 
619bb83316aSAugustin Cavalier 		// TODO: Increase/reset timeout? (We don't have any timeouts presently.)
620bb83316aSAugustin Cavalier 		return;
621bb83316aSAugustin Cavalier 	} else if (response.result != l2cap_connection_rsp::RESULT_SUCCESS) {
622bb83316aSAugustin Cavalier 		// Some error response.
623bb83316aSAugustin Cavalier 		// TODO: Translate `result` if possible?
624bb83316aSAugustin Cavalier 		socket->error = ECONNREFUSED;
625bb83316aSAugustin Cavalier 
626bb83316aSAugustin Cavalier 		fState = CLOSED;
627bb83316aSAugustin Cavalier 		fCommandWait.NotifyAll();
628bb83316aSAugustin Cavalier 	}
629bb83316aSAugustin Cavalier 
630bb83316aSAugustin Cavalier 	// Success: channel is now open for configuration.
631bb83316aSAugustin Cavalier 	fState = CONFIGURATION;
632bb83316aSAugustin Cavalier 	fDestinationChannelID = response.dcid;
633bb83316aSAugustin Cavalier 
634bb83316aSAugustin Cavalier 	_SendChannelConfig();
635bb83316aSAugustin Cavalier }
636bb83316aSAugustin Cavalier 
637bb83316aSAugustin Cavalier 
638bb83316aSAugustin Cavalier void
_SendChannelConfig()639bb83316aSAugustin Cavalier L2capEndpoint::_SendChannelConfig()
640bb83316aSAugustin Cavalier {
641bb83316aSAugustin Cavalier 	uint16* mtu = NULL;
642bb83316aSAugustin Cavalier 	if (fChannelConfig.incoming_mtu != L2CAP_MTU_DEFAULT)
643bb83316aSAugustin Cavalier 		mtu = &fChannelConfig.incoming_mtu;
644bb83316aSAugustin Cavalier 
645bb83316aSAugustin Cavalier 	uint16* flush_timeout = NULL;
646bb83316aSAugustin Cavalier 	if (fChannelConfig.flush_timeout != L2CAP_FLUSH_TIMEOUT_DEFAULT)
647bb83316aSAugustin Cavalier 		flush_timeout = &fChannelConfig.flush_timeout;
648bb83316aSAugustin Cavalier 
649bb83316aSAugustin Cavalier 	l2cap_qos* flow = NULL;
650bb83316aSAugustin Cavalier 	if (memcmp(&sDefaultQOS, &fChannelConfig.outgoing_flow,
651bb83316aSAugustin Cavalier 			sizeof(fChannelConfig.outgoing_flow)) != 0) {
652bb83316aSAugustin Cavalier 		flow = &fChannelConfig.outgoing_flow;
653bb83316aSAugustin Cavalier 	}
654bb83316aSAugustin Cavalier 
655bb83316aSAugustin Cavalier 	uint8 ident = btCoreData->allocate_command_ident(fConnection, this);
656bb83316aSAugustin Cavalier 	if (ident == L2CAP_NULL_IDENT) {
657bb83316aSAugustin Cavalier 		// TODO: Retry later?
658bb83316aSAugustin Cavalier 		return;
659bb83316aSAugustin Cavalier 	}
660bb83316aSAugustin Cavalier 
661bb83316aSAugustin Cavalier 	status_t status = send_l2cap_configuration_req(fConnection, ident,
662bb83316aSAugustin Cavalier 		fDestinationChannelID, 0, flush_timeout, mtu, flow);
663bb83316aSAugustin Cavalier 	if (status != B_OK) {
664bb83316aSAugustin Cavalier 		socket->error = status;
665bb83316aSAugustin Cavalier 		return;
666bb83316aSAugustin Cavalier 	}
667bb83316aSAugustin Cavalier 
668bb83316aSAugustin Cavalier 	fConfigState.out = ConfigState::SENT;
669bb83316aSAugustin Cavalier }
670bb83316aSAugustin Cavalier 
671bb83316aSAugustin Cavalier 
672bb83316aSAugustin Cavalier void
_HandleConfigurationReq(uint8 ident,uint16 flags,uint16 * mtu,uint16 * flush_timeout,l2cap_qos * flow)673bb83316aSAugustin Cavalier L2capEndpoint::_HandleConfigurationReq(uint8 ident, uint16 flags,
674bb83316aSAugustin Cavalier 	uint16* mtu, uint16* flush_timeout, l2cap_qos* flow)
675bb83316aSAugustin Cavalier {
676bb83316aSAugustin Cavalier 	CALLED();
677bb83316aSAugustin Cavalier 	MutexLocker locker(fLock);
678bb83316aSAugustin Cavalier 	fCommandWait.NotifyAll();
679bb83316aSAugustin Cavalier 
680bb83316aSAugustin Cavalier 	if (fState != CONFIGURATION && fState != OPEN) {
681bb83316aSAugustin Cavalier 		ERROR("l2cap: unexpected configuration req: invalid channel state (cid=%d, state=%d)\n",
682bb83316aSAugustin Cavalier 			fChannelID, fState);
683bb83316aSAugustin Cavalier 		send_l2cap_configuration_rsp(fConnection, ident, fChannelID, 0,
684bb83316aSAugustin Cavalier 			l2cap_configuration_rsp::RESULT_REJECTED, NULL);
685bb83316aSAugustin Cavalier 		return;
686bb83316aSAugustin Cavalier 	}
687bb83316aSAugustin Cavalier 
688bb83316aSAugustin Cavalier 	if (fState == OPEN) {
689bb83316aSAugustin Cavalier 		// Re-configuration.
690bb83316aSAugustin Cavalier 		fConfigState = {};
691bb83316aSAugustin Cavalier 		fState = CONFIGURATION;
692bb83316aSAugustin Cavalier 	}
693bb83316aSAugustin Cavalier 
694bb83316aSAugustin Cavalier 	// Process options.
695bb83316aSAugustin Cavalier 	// TODO: Validate parameters!
696bb83316aSAugustin Cavalier 	if (mtu != NULL && *mtu != fChannelConfig.outgoing_mtu)
697bb83316aSAugustin Cavalier 		fChannelConfig.outgoing_mtu = *mtu;
698bb83316aSAugustin Cavalier 	if (flush_timeout != NULL && *flush_timeout != fChannelConfig.flush_timeout)
699bb83316aSAugustin Cavalier 		fChannelConfig.flush_timeout = *flush_timeout;
700bb83316aSAugustin Cavalier 	if (flow != NULL)
701bb83316aSAugustin Cavalier 		fChannelConfig.incoming_flow = *flow;
702bb83316aSAugustin Cavalier 
703bb83316aSAugustin Cavalier 	send_l2cap_configuration_rsp(fConnection, ident, fChannelID, 0,
704bb83316aSAugustin Cavalier 		l2cap_configuration_rsp::RESULT_SUCCESS, NULL);
705bb83316aSAugustin Cavalier 
706bb83316aSAugustin Cavalier 	if ((flags & L2CAP_CFG_FLAG_CONTINUATION) != 0) {
707bb83316aSAugustin Cavalier 		// More options are coming, just keep waiting.
708bb83316aSAugustin Cavalier 		return;
709bb83316aSAugustin Cavalier 	}
710bb83316aSAugustin Cavalier 
711bb83316aSAugustin Cavalier 	// We now have all options.
712bb83316aSAugustin Cavalier 	fConfigState.in = ConfigState::DONE;
713bb83316aSAugustin Cavalier 
714bb83316aSAugustin Cavalier 	if (fConfigState.out < ConfigState::SENT)
715bb83316aSAugustin Cavalier 		_SendChannelConfig();
716bb83316aSAugustin Cavalier 	else if (fConfigState.out == ConfigState::DONE)
717bb83316aSAugustin Cavalier 		_MarkEstablished();
718bb83316aSAugustin Cavalier }
719bb83316aSAugustin Cavalier 
720bb83316aSAugustin Cavalier 
721bb83316aSAugustin Cavalier void
_HandleConfigurationRsp(uint8 ident,uint16 scid,uint16 flags,uint16 result,uint16 * mtu,uint16 * flush_timeout,l2cap_qos * flow)722bb83316aSAugustin Cavalier L2capEndpoint::_HandleConfigurationRsp(uint8 ident, uint16 scid, uint16 flags,
723bb83316aSAugustin Cavalier 	uint16 result, uint16* mtu, uint16* flush_timeout, l2cap_qos* flow)
724bb83316aSAugustin Cavalier {
725bb83316aSAugustin Cavalier 	CALLED();
726bb83316aSAugustin Cavalier 	MutexLocker locker(fLock);
727bb83316aSAugustin Cavalier 	fCommandWait.NotifyAll();
728bb83316aSAugustin Cavalier 
729bb83316aSAugustin Cavalier 	if (fState != CONFIGURATION) {
730bb83316aSAugustin Cavalier 		ERROR("l2cap: unexpected configuration rsp: invalid channel state (cid=%d, state=%d)\n",
731bb83316aSAugustin Cavalier 			fChannelID, fState);
732bb83316aSAugustin Cavalier 		send_l2cap_command_reject(fConnection, ident,
733bb83316aSAugustin Cavalier 			l2cap_command_reject::REJECTED_INVALID_CID, 0, scid, fChannelID);
734bb83316aSAugustin Cavalier 		return;
735bb83316aSAugustin Cavalier 	}
736*91e6e521SAugustin Cavalier 	if (scid != fChannelID) {
737bb83316aSAugustin Cavalier 		ERROR("l2cap: unexpected configuration rsp: invalid source channel (cid=%d, scid=%d)\n",
738bb83316aSAugustin Cavalier 			fChannelID, scid);
739bb83316aSAugustin Cavalier 		send_l2cap_command_reject(fConnection, ident,
740bb83316aSAugustin Cavalier 			l2cap_command_reject::REJECTED_INVALID_CID, 0, scid, fChannelID);
741bb83316aSAugustin Cavalier 		return;
742bb83316aSAugustin Cavalier 	}
743bb83316aSAugustin Cavalier 
744bb83316aSAugustin Cavalier 	// TODO: Validate parameters!
745bb83316aSAugustin Cavalier 	if (result == l2cap_configuration_rsp::RESULT_PENDING) {
746bb83316aSAugustin Cavalier 		// We will receive another CONFIGURATION_RSP later.
747bb83316aSAugustin Cavalier 		return;
748bb83316aSAugustin Cavalier 	} else if (result == l2cap_configuration_rsp::RESULT_UNACCEPTABLE_PARAMS) {
749bb83316aSAugustin Cavalier 		// The acceptable parameters are specified in options.
750bb83316aSAugustin Cavalier 		if (mtu != NULL && *mtu != fChannelConfig.incoming_mtu)
751bb83316aSAugustin Cavalier 			fChannelConfig.incoming_mtu = *mtu;
752bb83316aSAugustin Cavalier 		if (flush_timeout != NULL && *flush_timeout != fChannelConfig.flush_timeout)
753bb83316aSAugustin Cavalier 			fChannelConfig.flush_timeout = *flush_timeout;
754bb83316aSAugustin Cavalier 	} else if (result == l2cap_configuration_rsp::RESULT_FLOW_SPEC_REJECTED) {
755bb83316aSAugustin Cavalier 		if (flow != NULL)
756bb83316aSAugustin Cavalier 			fChannelConfig.outgoing_flow = *flow;
757bb83316aSAugustin Cavalier 	} else if (result != l2cap_configuration_rsp::RESULT_SUCCESS) {
758bb83316aSAugustin Cavalier 		ERROR("l2cap: unhandled configuration response! (result=%d)\n",
759bb83316aSAugustin Cavalier 			result);
760bb83316aSAugustin Cavalier 		return;
761bb83316aSAugustin Cavalier 	}
762bb83316aSAugustin Cavalier 
763bb83316aSAugustin Cavalier 	if ((flags & L2CAP_CFG_FLAG_CONTINUATION) != 0) {
764bb83316aSAugustin Cavalier 		// More options are coming, just keep waiting.
765bb83316aSAugustin Cavalier 		return;
766bb83316aSAugustin Cavalier 	}
767bb83316aSAugustin Cavalier 
768bb83316aSAugustin Cavalier 	if (result != l2cap_configuration_rsp::RESULT_SUCCESS) {
769bb83316aSAugustin Cavalier 		// Resend configuration request to try again.
770bb83316aSAugustin Cavalier 		_SendChannelConfig();
771bb83316aSAugustin Cavalier 		return;
772bb83316aSAugustin Cavalier 	}
773bb83316aSAugustin Cavalier 
774bb83316aSAugustin Cavalier 	// We now have all options.
775bb83316aSAugustin Cavalier 	fConfigState.out = ConfigState::DONE;
776bb83316aSAugustin Cavalier 
777bb83316aSAugustin Cavalier 	if (fConfigState.in == ConfigState::DONE)
778bb83316aSAugustin Cavalier 		_MarkEstablished();
779ef36d964SOliver Ruiz Dorantes }
780ef36d964SOliver Ruiz Dorantes 
781ef36d964SOliver Ruiz Dorantes 
782a58b3b32SOliver Ruiz Dorantes status_t
_MarkEstablished()783bb83316aSAugustin Cavalier L2capEndpoint::_MarkEstablished()
784a58b3b32SOliver Ruiz Dorantes {
785c58e1d7fSAlexander von Gluck IV 	CALLED();
786bb83316aSAugustin Cavalier 	ASSERT_LOCKED_MUTEX(&fLock);
787bb83316aSAugustin Cavalier 
788bb83316aSAugustin Cavalier 	fState = OPEN;
789bb83316aSAugustin Cavalier 	fCommandWait.NotifyAll();
790a58b3b32SOliver Ruiz Dorantes 
791c58e1d7fSAlexander von Gluck IV 	status_t error = B_OK;
792bb83316aSAugustin Cavalier 	if (gSocketModule->has_parent(socket)) {
793ef36d964SOliver Ruiz Dorantes 		error = gSocketModule->set_connected(socket);
79431f87630SOliver Ruiz Dorantes 		if (error == B_OK) {
795bb83316aSAugustin Cavalier 			release_sem(fAcceptSemaphore);
796bb83316aSAugustin Cavalier 			fAcceptSemaphore = -1;
79731f87630SOliver Ruiz Dorantes 		} else {
798bb83316aSAugustin Cavalier 			ERROR("%s: could not set endpoint %p connected: %s\n", __func__, this,
799c58e1d7fSAlexander von Gluck IV 				strerror(error));
80031f87630SOliver Ruiz Dorantes 		}
801bb83316aSAugustin Cavalier 	}
802a58b3b32SOliver Ruiz Dorantes 
803a58b3b32SOliver Ruiz Dorantes 	return error;
8047cc7cadaSOliver Ruiz Dorantes }
80531f87630SOliver Ruiz Dorantes 
80631f87630SOliver Ruiz Dorantes 
807bb83316aSAugustin Cavalier void
_HandleDisconnectionReq(uint8 ident,uint16 scid)808bb83316aSAugustin Cavalier L2capEndpoint::_HandleDisconnectionReq(uint8 ident, uint16 scid)
80931f87630SOliver Ruiz Dorantes {
810c58e1d7fSAlexander von Gluck IV 	CALLED();
811bb83316aSAugustin Cavalier 	MutexLocker locker(fLock);
812bb83316aSAugustin Cavalier 	fCommandWait.NotifyAll();
813c58e1d7fSAlexander von Gluck IV 
814bb83316aSAugustin Cavalier 	if (scid != fDestinationChannelID) {
815bb83316aSAugustin Cavalier 		ERROR("l2cap: unexpected disconnection req: invalid source channel (cid=%d, scid=%d)\n",
816bb83316aSAugustin Cavalier 			fChannelID, scid);
817bb83316aSAugustin Cavalier 		send_l2cap_command_reject(fConnection, ident,
818bb83316aSAugustin Cavalier 			l2cap_command_reject::REJECTED_INVALID_CID, 0, scid, fChannelID);
819bb83316aSAugustin Cavalier 		return;
820bb83316aSAugustin Cavalier 	}
821bb83316aSAugustin Cavalier 
822bb83316aSAugustin Cavalier 	if (fState != WAIT_FOR_DISCONNECTION_RSP)
823bb83316aSAugustin Cavalier 		fState = RECEIVED_DISCONNECTION_REQ;
824bb83316aSAugustin Cavalier 
825bb83316aSAugustin Cavalier 	// The dcid/scid are the same as in the REQ command.
826bb83316aSAugustin Cavalier 	status_t status = send_l2cap_disconnection_rsp(fConnection, ident, fChannelID, scid);
827bb83316aSAugustin Cavalier 	if (status != B_OK) {
828bb83316aSAugustin Cavalier 		// TODO?
829bb83316aSAugustin Cavalier 		return;
830bb83316aSAugustin Cavalier 	}
831bb83316aSAugustin Cavalier 
832bb83316aSAugustin Cavalier 	_MarkClosed();
833bb83316aSAugustin Cavalier }
834bb83316aSAugustin Cavalier 
835bb83316aSAugustin Cavalier 
836bb83316aSAugustin Cavalier void
_HandleDisconnectionRsp(uint8 ident,uint16 dcid,uint16 scid)837bb83316aSAugustin Cavalier L2capEndpoint::_HandleDisconnectionRsp(uint8 ident, uint16 dcid, uint16 scid)
838bb83316aSAugustin Cavalier {
839bb83316aSAugustin Cavalier 	CALLED();
840bb83316aSAugustin Cavalier 	MutexLocker locker(fLock);
841bb83316aSAugustin Cavalier 	fCommandWait.NotifyAll();
842bb83316aSAugustin Cavalier 
843bb83316aSAugustin Cavalier 	if (fState != WAIT_FOR_DISCONNECTION_RSP) {
844bb83316aSAugustin Cavalier 		ERROR("l2cap: unexpected disconnection rsp (cid=%d, scid=%d)\n",
845bb83316aSAugustin Cavalier 			fChannelID, scid);
846bb83316aSAugustin Cavalier 		send_l2cap_command_reject(fConnection, ident,
847bb83316aSAugustin Cavalier 			l2cap_command_reject::REJECTED_INVALID_CID, 0, scid, fChannelID);
848bb83316aSAugustin Cavalier 		return;
849bb83316aSAugustin Cavalier 	}
850bb83316aSAugustin Cavalier 
851bb83316aSAugustin Cavalier 	if (dcid != fDestinationChannelID && scid != fChannelID) {
852bb83316aSAugustin Cavalier 		ERROR("l2cap: unexpected disconnection rsp: mismatched CIDs (dcid=%d, scid=%d)\n",
853bb83316aSAugustin Cavalier 			dcid, scid);
854bb83316aSAugustin Cavalier 		return;
855bb83316aSAugustin Cavalier 	}
856bb83316aSAugustin Cavalier 
857bb83316aSAugustin Cavalier 	_MarkClosed();
858bb83316aSAugustin Cavalier }
859bb83316aSAugustin Cavalier 
860bb83316aSAugustin Cavalier 
861bb83316aSAugustin Cavalier void
_MarkClosed()862bb83316aSAugustin Cavalier L2capEndpoint::_MarkClosed()
863bb83316aSAugustin Cavalier {
864bb83316aSAugustin Cavalier 	CALLED();
865bb83316aSAugustin Cavalier 	ASSERT_LOCKED_MUTEX(&fLock);
8668638173cSOliver Ruiz Dorantes 
86731f87630SOliver Ruiz Dorantes 	fState = CLOSED;
86831f87630SOliver Ruiz Dorantes 
869bb83316aSAugustin Cavalier 	gL2capEndpointManager.UnbindFromChannel(this);
87031f87630SOliver Ruiz Dorantes }
871