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