1/*
2 * Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5#include "L2capEndpoint.h"
6#include "l2cap_address.h"
7#include "l2cap_upper.h"
8#include "l2cap_lower.h"
9
10#include <stdio.h>
11#include <string.h>
12#include <sys/stat.h>
13
14#include <bluetooth/bdaddrUtils.h>
15#include <bluetooth/L2CAP/btL2CAP.h>
16
17#define BT_DEBUG_THIS_MODULE
18#define MODULE_NAME "l2cap"
19#define SUBMODULE_NAME "Endpoint"
20#define SUBMODULE_COLOR 32
21#include <btDebug.h>
22
23
24static inline bigtime_t
25absolute_timeout(bigtime_t timeout)
26{
27	if (timeout == 0 || timeout == B_INFINITE_TIMEOUT)
28		return timeout;
29
30	// TODO: Make overflow safe!
31	return timeout + system_time();
32}
33
34
35L2capEndpoint::L2capEndpoint(net_socket* socket)
36	:
37	ProtocolSocket(socket),
38	fConfigurationSet(false),
39	fEstablishSemaphore(-1),
40	fPeerEndpoint(NULL),
41	fChannel(NULL)
42{
43	debugf("[%ld] %p\n", find_thread(NULL), this);
44
45	/* Set MTU and flow control settings to defaults */
46	fConfiguration.imtu = L2CAP_MTU_DEFAULT;
47	memcpy(&fConfiguration.iflow, &default_qos , sizeof(l2cap_flow_t) );
48
49	fConfiguration.omtu = L2CAP_MTU_DEFAULT;
50	memcpy(&fConfiguration.oflow, &default_qos , sizeof(l2cap_flow_t) );
51
52	fConfiguration.flush_timo = L2CAP_FLUSH_TIMO_DEFAULT;
53	fConfiguration.link_timo  = L2CAP_LINK_TIMO_DEFAULT;
54
55	// TODO: XXX not for listening endpoints, imtu should be known first
56	gStackModule->init_fifo(&fReceivingFifo, "l2cap recvfifo", L2CAP_MTU_DEFAULT);
57}
58
59
60L2capEndpoint::~L2capEndpoint()
61{
62	debugf("[%ld] %p\n", find_thread(NULL), this);
63
64	gStackModule->uninit_fifo(&fReceivingFifo);
65}
66
67
68status_t
69L2capEndpoint::Init()
70{
71	debugf("[%ld] %p\n", find_thread(NULL), this);
72
73	return B_OK;
74}
75
76
77void
78L2capEndpoint::Uninit()
79{
80	debugf("[%ld] %p\n", find_thread(NULL), this);
81
82}
83
84
85status_t
86L2capEndpoint::Open()
87{
88	debugf("[%ld] %p\n", find_thread(NULL), this);
89
90	status_t error = ProtocolSocket::Open();
91	if (error != B_OK)
92		return error;
93
94	return B_OK;
95}
96
97
98status_t
99L2capEndpoint::Close()
100{
101	debugf("[%ld] %p\n", find_thread(NULL), this);
102
103	if (fChannel == NULL) {
104		// TODO: Parent socket
105
106	} else {
107		// Child Socket
108		if (fState == CLOSED) {
109			debugf("Already closed by peer %p\n", this);
110			// TODO: Clean needed stuff
111			return B_OK;
112		} else {
113			// Issue Disconnection request over the channel
114			MarkClosed();
115
116			bigtime_t timeout = absolute_timeout(300 * 1000 * 1000);
117
118			status_t error = l2cap_upper_dis_req(fChannel);
119
120			if (error != B_OK)
121				return error;
122
123			return acquire_sem_etc(fEstablishSemaphore, 1,
124				B_ABSOLUTE_TIMEOUT | B_CAN_INTERRUPT, timeout);
125		}
126	}
127
128	if (fEstablishSemaphore != -1) {
129		delete_sem(fEstablishSemaphore);
130	}
131
132	return B_OK;
133}
134
135
136status_t
137L2capEndpoint::Free()
138{
139	debugf("[%ld] %p\n", find_thread(NULL), this);
140
141	return B_OK;
142}
143
144
145status_t
146L2capEndpoint::Bind(const struct sockaddr* _address)
147{
148	const sockaddr_l2cap* address
149		= reinterpret_cast<const sockaddr_l2cap*>(_address);
150
151	if (_address == NULL)
152		return B_ERROR;
153
154	if (address->l2cap_family != AF_BLUETOOTH )
155		return EAFNOSUPPORT;
156
157	if (address->l2cap_len != sizeof(struct sockaddr_l2cap))
158		return EAFNOSUPPORT;
159
160	// TODO: Check if that PSM is already bound
161	// return EADDRINUSE;
162
163	// TODO: Check if the PSM is valid, check assigned numbers document for valid
164	// psm available to applications.
165	// All PSM values shall be ODD, that is, the least significant bit of the least
166	// significant octet must be ’1’. Also, all PSM values shall have the least
167	// significant bit of the most significant octet equal to ’0’. This allows
168	// the PSM field to be extended beyond 16 bits.
169	if ((address->l2cap_psm & 1) == 0)
170		return B_ERROR;
171
172	memcpy(&socket->address, _address, sizeof(struct sockaddr_l2cap));
173	socket->address.ss_len = sizeof(struct sockaddr_l2cap);
174
175	debugf("for %s psm=%d\n", bdaddrUtils::ToString(address->l2cap_bdaddr),
176		address->l2cap_psm);
177
178	fState = BOUND;
179
180	return B_OK;
181}
182
183
184status_t
185L2capEndpoint::Unbind()
186{
187	debugf("[%ld] %p\n", find_thread(NULL), this);
188
189	return B_OK;
190}
191
192
193status_t
194L2capEndpoint::Listen(int backlog)
195{
196	debugf("[%ld] %p\n", find_thread(NULL), this);
197
198	if (fState != BOUND) {
199		debugf("Invalid State %p\n", this);
200		return B_BAD_VALUE;
201	}
202
203	fEstablishSemaphore = create_sem(0, "l2cap serv accept");
204	if (fEstablishSemaphore < B_OK) {
205		flowf("Semaphore could not be created\n");
206		return ENOBUFS;
207	}
208
209	gSocketModule->set_max_backlog(socket, backlog);
210
211	fState = LISTEN;
212
213	return B_OK;
214}
215
216
217status_t
218L2capEndpoint::Connect(const struct sockaddr* _address)
219{
220	const sockaddr_l2cap* address
221		= reinterpret_cast<const sockaddr_l2cap*>(_address);
222
223	if (address->l2cap_len != sizeof(*address))
224		return EINVAL;
225
226	// Check for any specific status?
227	if (fState == CONNECTING) {
228		return EINPROGRESS;
229	}
230
231	// TODO: should not be in the BOUND status first?
232
233	debugf("[%ld] %p->L2capEndpoint::Connect(\"%s\")\n", find_thread(NULL),
234		this, ConstSocketAddress(&gL2cap4AddressModule, _address)
235		.AsString().Data());
236
237	// TODO: If we were bound to a specific source address
238
239	// Route, we must find a Connection descriptor with address->l2cap_address
240	hci_id hid = btCoreData->RouteConnection(address->l2cap_bdaddr);
241
242	debugf("%lx for route %s\n", hid,
243		bdaddrUtils::ToString(address->l2cap_bdaddr));
244
245	if (hid > 0) {
246		HciConnection* connection = btCoreData->ConnectionByDestination(
247			address->l2cap_bdaddr, hid);
248
249		L2capChannel* channel = btCoreData->AddChannel(connection,
250			address->l2cap_psm);
251
252		if (channel == NULL)
253			return ENOMEM;
254
255		// Send connection request
256		if (l2cap_upper_con_req(channel) == B_OK) {
257			fState = CONNECTING;
258
259			BindToChannel(channel);
260
261			fEstablishSemaphore = create_sem(0, "l2cap client");
262			if (fEstablishSemaphore < B_OK) {
263				flowf("Semaphore could not be created\n");
264				return ENOBUFS;
265			}
266
267			bigtime_t timeout = absolute_timeout(300 * 1000 * 1000);
268
269			return acquire_sem_etc(fEstablishSemaphore, 1,
270				B_ABSOLUTE_TIMEOUT | B_CAN_INTERRUPT, timeout);
271
272		} else {
273			return ECONNREFUSED;
274		}
275	}
276
277	return ENETUNREACH;
278}
279
280
281status_t
282L2capEndpoint::Accept(net_socket** _acceptedSocket)
283{
284	debugf("[%ld]\n", find_thread(NULL));
285
286	// MutexLocker locker(fLock);
287
288	status_t status;
289	bigtime_t timeout = absolute_timeout(300 * 1000 * 1000);
290
291	do {
292		// locker.Unlock();
293
294		status = acquire_sem_etc(fEstablishSemaphore, 1, B_ABSOLUTE_TIMEOUT
295			| B_CAN_INTERRUPT, timeout);
296
297		if (status != B_OK)
298			return status;
299
300		// locker.Lock();
301		status = gSocketModule->dequeue_connected(socket, _acceptedSocket);
302
303		if (status != B_OK) {
304			debugf("Could not dequeue socket %s\n", strerror(status));
305		} else {
306
307			((L2capEndpoint*)((*_acceptedSocket)->first_protocol))->fState = ESTABLISHED;
308			// unassign any channel for the parent endpoint
309			fChannel = NULL;
310			// we are listening again
311			fState = LISTEN;
312		}
313
314	} while (status != B_OK);
315
316	return status;
317}
318
319
320ssize_t
321L2capEndpoint::Send(const iovec* vecs, size_t vecCount,
322	ancillary_data_container* ancillaryData)
323{
324	debugf("[%ld] %p Send(%p, %ld, %p)\n", find_thread(NULL),
325		this, vecs, vecCount, ancillaryData);
326
327	return B_OK;
328}
329
330
331ssize_t
332L2capEndpoint::Receive(const iovec* vecs, size_t vecCount,
333	ancillary_data_container** _ancillaryData, struct sockaddr* _address,
334	socklen_t* _addressLength)
335{
336	debugf("[%ld] %p Receive(%p, %ld)\n", find_thread(NULL),
337		this, vecs, vecCount);
338
339	if (fState != ESTABLISHED) {
340		debugf("Invalid State %p\n", this);
341		return B_BAD_VALUE;
342	}
343
344	return B_OK;
345}
346
347
348ssize_t
349L2capEndpoint::ReadData(size_t numBytes, uint32 flags, net_buffer** _buffer)
350{
351	debugf("e->%p num=%ld, f=%ld)\n", this, numBytes, flags);
352
353	if (fState != ESTABLISHED) {
354		debugf("Invalid State %p\n", this);
355		return B_BAD_VALUE;
356	}
357
358	return gStackModule->fifo_dequeue_buffer(&fReceivingFifo, flags,
359		B_INFINITE_TIMEOUT, _buffer);
360}
361
362
363ssize_t
364L2capEndpoint::SendData(net_buffer* buffer)
365{
366	debugf("size=%ld\n", buffer->size);
367
368	if (fState != ESTABLISHED) {
369		debugf("Invalid State %p\n", this);
370		return B_BAD_VALUE;
371	}
372
373	btCoreData->SpawnFrame(fChannel->conn, fChannel, buffer, L2CAP_B_FRAME);
374
375	SchedConnectionPurgeThread(fChannel->conn);
376
377	// TODO: Report bytes sent?
378	return B_OK;
379}
380
381
382ssize_t
383L2capEndpoint::Sendable()
384{
385	debugf("[%ld] %p\n", find_thread(NULL), this);
386
387	return B_OK;
388}
389
390
391ssize_t
392L2capEndpoint::Receivable()
393{
394	debugf("[%ld] %p\n", find_thread(NULL), this);
395
396	return 0;
397}
398
399
400L2capEndpoint*
401L2capEndpoint::ForPsm(uint16 psm)
402{
403	L2capEndpoint* endpoint;
404
405	DoublyLinkedList<L2capEndpoint>::Iterator iterator
406		= EndpointList.GetIterator();
407
408	while (iterator.HasNext()) {
409
410		endpoint = iterator.Next();
411		if (((struct sockaddr_l2cap*)&endpoint->socket->address)->l2cap_psm == psm
412			&& endpoint->fState == LISTEN) {
413			// TODO endpoint ocupied, lock it! define a channel for it
414			return endpoint;
415		}
416	}
417
418	return NULL;
419}
420
421
422void
423L2capEndpoint::BindNewEnpointToChannel(L2capChannel* channel)
424{
425	net_socket* newSocket;
426	status_t error = gSocketModule->spawn_pending_socket(socket, &newSocket);
427	if (error != B_OK) {
428		debugf("Could not spawn child for Endpoint %p\n", this);
429		// TODO: Handle situation
430		return;
431	}
432
433	L2capEndpoint* endpoint = (L2capEndpoint*)newSocket->first_protocol;
434
435	endpoint->fChannel = channel;
436	endpoint->fPeerEndpoint = this;
437
438	channel->endpoint = endpoint;
439
440	debugf("new socket %p/e->%p from parent %p/e->%p\n",
441		newSocket, endpoint, socket, this);
442
443	// Provide the channel the configuration set by the user socket
444	channel->configuration = &fConfiguration;
445
446	// It might be used keep the last negotiated channel
447	// fChannel = channel;
448
449	debugf("New endpoint %p for psm %d, schannel %x dchannel %x\n", endpoint,
450		channel->psm, channel->scid, channel->dcid);
451}
452
453
454void
455L2capEndpoint::BindToChannel(L2capChannel* channel)
456{
457	this->fChannel = channel;
458	channel->endpoint = this;
459
460	// Provide the channel the configuration set by the user socket
461	channel->configuration = &fConfiguration;
462
463	// no parent to give feedback
464	fPeerEndpoint = NULL;
465}
466
467
468status_t
469L2capEndpoint::MarkEstablished()
470{
471	status_t error = B_OK;
472	debugf("Endpoint %p for psm %d, schannel %x dchannel %x\n", this,
473		fChannel->psm, fChannel->scid, fChannel->dcid);
474
475	fChannel->state = L2CAP_CHAN_OPEN;
476	fState = ESTABLISHED;
477
478	if (fPeerEndpoint != NULL) {
479
480		error = gSocketModule->set_connected(socket);
481		if (error == B_OK) {
482			release_sem(fPeerEndpoint->fEstablishSemaphore);
483		} else {
484			debugf("Could not set child Endpoint %p %s\n", this, strerror(error));
485		}
486	} else
487		release_sem(fEstablishSemaphore);
488
489	return error;
490}
491
492
493status_t
494L2capEndpoint::MarkClosed()
495{
496	flowf("\n");
497	if (fState == CLOSED) {
498		release_sem(fEstablishSemaphore);
499	}
500
501	fState = CLOSED;
502
503	return B_OK;
504}
505