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
absolute_timeout(bigtime_t timeout)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
posix_error(status_t error)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
L2capEndpoint(net_socket * socket)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
~L2capEndpoint()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
_WaitForStateChange(bigtime_t absoluteTimeout)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
Open()118 L2capEndpoint::Open()
119 {
120 CALLED();
121 return ProtocolSocket::Open();
122 }
123
124
125 status_t
Shutdown()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
Close()183 L2capEndpoint::Close()
184 {
185 return Shutdown();
186 }
187
188
189 status_t
Free()190 L2capEndpoint::Free()
191 {
192 CALLED();
193
194 return B_OK;
195 }
196
197
198 status_t
Bind(const struct sockaddr * _address)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
Unbind()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
Listen(int backlog)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
Connect(const struct sockaddr * _address)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
Accept(net_socket ** _acceptedSocket)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
ReadData(size_t numBytes,uint32 flags,net_buffer ** _buffer)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
SendData(net_buffer * buffer)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
ReceiveData(net_buffer * buffer)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
_SendTimer(net_timer * timer,void * _endpoint)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
_SendQueued()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
Sendable()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
Receivable()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
_HandleCommandRejected(uint8 ident,uint16 reason,const l2cap_command_reject_data & data)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
_HandleConnectionReq(HciConnection * connection,uint8 ident,uint16 psm,uint16 scid)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
_HandleConnectionRsp(uint8 ident,const l2cap_connection_rsp & response)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
_SendChannelConfig()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
_HandleConfigurationReq(uint8 ident,uint16 flags,uint16 * mtu,uint16 * flush_timeout,l2cap_qos * flow)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
_HandleConfigurationRsp(uint8 ident,uint16 scid,uint16 flags,uint16 result,uint16 * mtu,uint16 * flush_timeout,l2cap_qos * flow)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
_MarkEstablished()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
_HandleDisconnectionReq(uint8 ident,uint16 scid)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
_HandleDisconnectionRsp(uint8 ident,uint16 dcid,uint16 scid)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
_MarkClosed()862 L2capEndpoint::_MarkClosed()
863 {
864 CALLED();
865 ASSERT_LOCKED_MUTEX(&fLock);
866
867 fState = CLOSED;
868
869 gL2capEndpointManager.UnbindFromChannel(this);
870 }
871