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 */
6/*-
7 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18*/
19#include <KernelExport.h>
20#include <string.h>
21#include <lock.h>
22
23#include <NetBufferUtilities.h>
24
25#include <bluetooth/HCI/btHCI_transport.h>
26
27#include <btModules.h>
28#include <l2cap.h>
29
30#include "l2cap_internal.h"
31#include "l2cap_signal.h"
32#include "l2cap_upper.h"
33
34#define BT_DEBUG_THIS_MODULE
35#define SUBMODULE_NAME "lower"
36#define SUBMODULE_COLOR 36
37#include <btDebug.h>
38
39status_t
40l2cap_receive(HciConnection* conn, net_buffer* buffer)
41{
42	status_t error = B_OK;
43	uint16 dcid;
44	uint16 length;
45
46#ifdef DUMP_L2CAP_FRAME
47	flowf("DUMP:");
48	for (uint i = 0; i < buffer->size; i++) {
49		uint8 c = 0;
50		gBufferModule->read(buffer, i, &c, 1);
51		dprintf("[%x]", c);
52	}
53	dprintf("\n");
54#endif
55	// Check packet
56	if (buffer->size < sizeof(l2cap_hdr_t)) {
57		debugf("invalid L2CAP packet. Packet too small, len=%ld\n", buffer->size);
58		gBufferModule->free(buffer);
59		return EMSGSIZE;
60
61	}
62
63	// Get L2CAP header
64	NetBufferHeaderReader<l2cap_hdr_t> bufferHeader(buffer);
65	status_t status = bufferHeader.Status();
66	if (status < B_OK) {
67		return ENOBUFS;
68	}
69
70	length = bufferHeader->length = le16toh(bufferHeader->length);
71	dcid = bufferHeader->dcid = le16toh(bufferHeader->dcid);
72
73	debugf("len=%d cid=%x\n", length, dcid);
74
75	bufferHeader.Remove(); // pulling
76
77	// Check payload size
78	if (length != buffer->size ) {
79		debugf("Payload length mismatch, packetlen=%d, bufferlen=%ld\n",
80			length, buffer->size);
81		gBufferModule->free(buffer);
82		return EMSGSIZE;
83	}
84
85	// Process packet
86	switch (dcid) {
87		case L2CAP_SIGNAL_CID: // L2CAP command
88			error = l2cap_process_signal_cmd(conn, buffer);
89		break;
90
91		case L2CAP_CLT_CID: // Connectionless packet
92			// error = l2cap_cl_receive(buffer);
93			flowf("CL FRAME!!\n");
94		break;
95
96		default: // Data packet
97			error = l2cap_co_receive(conn, buffer, dcid);
98		break;
99	}
100
101	return (error);
102
103}
104
105
106struct bt_hci_module_info* btDevices = NULL;
107
108#if 0
109#pragma mark - thread conn sched -
110#endif
111
112static thread_id sConnectionThread;
113
114
115static void
116AddL2capHeader(L2capFrame* frame)
117{
118	NetBufferPrepend<l2cap_hdr_t> bufferHeader(frame->buffer);
119	status_t status = bufferHeader.Status();
120
121	if (status < B_OK) {
122		debugf("header could not be prepended! code=%d\n", frame->code);
123		return;
124	}
125
126	// fill
127	bufferHeader->length = htole16(frame->buffer->size - sizeof(l2cap_hdr_t));
128	switch (frame->type) {
129		case L2CAP_C_FRAME:
130			bufferHeader->dcid = L2CAP_SIGNAL_CID;
131		break;
132		case L2CAP_G_FRAME:
133			bufferHeader->dcid = L2CAP_CLT_CID;
134		break;
135		default:
136			bufferHeader->dcid = frame->channel->dcid;
137		break;
138	}
139}
140
141
142void
143purge_connection(HciConnection* conn)
144{
145	L2capFrame* frame;
146	bool containerCanBeDestroyed;
147
148	debugf("handle=%d\n", conn->handle);
149
150	mutex_lock(&conn->fLock);
151
152	frame = conn->OutGoingFrames.RemoveHead();
153
154	mutex_unlock(&conn->fLock);
155
156//	while ( frame != NULL) {
157
158		// Here is the place to decide how many l2cap signals we want to have
159		// per l2cap packet. 1 ATM
160		if (frame->type == L2CAP_C_FRAME && IS_SIGNAL_REQ(frame->code)) {
161			btCoreData->TimeoutSignal(frame, bluetooth_l2cap_rtx_timeout);
162			btCoreData->QueueSignal(frame);
163			containerCanBeDestroyed = false;
164		} else
165			containerCanBeDestroyed = true;
166
167		// Add the l2cap header
168		if (frame->buffer == NULL)
169			panic("Malformed frame in ongoing queue");
170
171		AddL2capHeader(frame);
172
173		if (btDevices == NULL)
174		if (get_module(BT_HCI_MODULE_NAME, (module_info**)&btDevices) != B_OK) {
175			panic("l2cap: cannot get dev module");
176		} // TODO: someone put it
177
178
179		debugf("type=%d, code=%d frame %p tolower\n", frame->type, frame->code,
180			frame->buffer);
181
182		frame->buffer->type = conn->handle;
183		btDevices->PostACL(conn->ndevice->index, frame->buffer);
184
185		// Only in the case that we need a response the frame container needs
186		// to be kept: Request C-Frames
187		if (containerCanBeDestroyed) {
188			delete frame;
189		}
190
191//		frame = conn->OutGoingFrames.RemoveHead();
192//	}
193
194}
195
196
197static status_t
198connection_thread(void*)
199{
200	int32 code;
201	ssize_t	ssizePort;
202	ssize_t	ssizeRead;
203
204	HciConnection* conn = NULL;
205
206	// TODO: Keep this a static var
207	port_id fPort = find_port(BLUETOOTH_CONNECTION_SCHED_PORT);
208	if (fPort == B_NAME_NOT_FOUND)
209	{
210		panic("BT Connection port has been deleted");
211	}
212
213	while ((ssizePort = port_buffer_size(fPort)) != B_BAD_PORT_ID) {
214
215		if (ssizePort <= 0) {
216			debugf("Error %s\n", strerror(ssizePort));
217			snooze(500 * 1000);
218			continue;
219		}
220
221		if (ssizePort > (ssize_t) sizeof(conn)) {
222			debugf("Message too big %ld\n", ssizePort);
223			snooze(500 * 1000);
224			continue;
225		}
226
227		ssizeRead = read_port(fPort, &code, &conn, ssizePort);
228
229		if (ssizeRead != ssizePort) {
230			debugf("Missmatch size port=%ld read=%ld\n", ssizePort, ssizeRead);
231			snooze(500 * 1000);
232			continue;
233		}
234
235		purge_connection(conn);
236	}
237
238	return B_OK;
239}
240
241
242status_t
243InitializeConnectionPurgeThread()
244{
245
246	port_id fPort = find_port(BLUETOOTH_CONNECTION_SCHED_PORT);
247	if (fPort == B_NAME_NOT_FOUND)
248	{
249		fPort = create_port(16, BLUETOOTH_CONNECTION_SCHED_PORT);
250		debugf("Connection purge port created %ld\n",fPort);
251	}
252
253	// This thread has to catch up connections before first package is sent.
254	sConnectionThread = spawn_kernel_thread(connection_thread,
255				"bluetooth connection purge", B_URGENT_DISPLAY_PRIORITY, NULL);
256
257	if (sConnectionThread >= B_OK)
258		return resume_thread(sConnectionThread);
259	else
260		return B_ERROR;
261}
262
263
264status_t
265QuitConnectionPurgeThread()
266{
267	status_t status;
268
269	port_id fPort = find_port(BLUETOOTH_CONNECTION_SCHED_PORT);
270	if (fPort != B_NAME_NOT_FOUND)
271		close_port(fPort);
272
273	flowf("Connection port deleted\n");
274	wait_for_thread(sConnectionThread, &status);
275	return status;
276}
277
278
279void
280SchedConnectionPurgeThread(HciConnection* conn)
281{
282	port_id port = find_port(BLUETOOTH_CONNECTION_SCHED_PORT);
283
284	HciConnection* temp = conn;
285
286	if (port == B_NAME_NOT_FOUND)
287		panic("BT Connection Port Deleted");
288
289	status_t error = write_port(port, (uint32) conn, &temp, sizeof(conn));
290
291	if (error != B_OK)
292		panic("BT Connection sched failed");
293
294}
295