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 <KernelExport.h>
6#include <NetBufferUtilities.h>
7
8#include "l2cap_internal.h"
9#include "l2cap_signal.h"
10#include "l2cap_command.h"
11#include "l2cap_lower.h"
12
13#include "L2capEndpoint.h"
14
15#define BT_DEBUG_THIS_MODULE
16#define SUBMODULE_NAME "upper"
17#define SUBMODULE_COLOR 36
18#include <btDebug.h>
19#include <l2cap.h>
20
21
22#if 0
23#pragma mark - Signals from the other pair
24#endif
25
26
27status_t
28l2cap_l2ca_con_ind(L2capChannel* channel)
29{
30	L2capEndpoint* endpoint = L2capEndpoint::ForPsm(channel->psm);
31
32	if (endpoint == NULL) { // TODO: refuse connection no endpoint bound
33		debugf("No endpoint bound for psm %d\n", channel->psm);
34		return B_ERROR;
35	}
36
37	// Pair Channel with endpoint
38	endpoint->BindNewEnpointToChannel(channel);
39
40	net_buffer* buf = l2cap_con_rsp(channel->ident, channel->scid, channel->dcid,
41		L2CAP_SUCCESS, L2CAP_NO_INFO);
42	L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf,
43		channel->ident, L2CAP_CON_RSP);
44	if (cmd == NULL) {
45		gBufferModule->free(buf);
46		return ENOMEM;
47	}
48
49	// we can move to configuration...
50	channel->state = L2CAP_CHAN_CONFIG;
51
52	// Link command to the queue
53	SchedConnectionPurgeThread(channel->conn);
54	return B_OK;
55}
56
57
58status_t
59l2cap_con_rsp_ind(HciConnection* conn, L2capChannel* channel)
60{
61	uint16* flush_timo = NULL;
62	uint16* mtu = NULL;
63	l2cap_flow_t* flow = NULL;
64
65	flowf("\n");
66
67	// We received a configuration response, connection process
68	// is a step further but still configuration pending
69
70	// Check channel state
71	if (channel->state != L2CAP_CHAN_OPEN && channel->state != L2CAP_CHAN_CONFIG) {
72		debugf("unexpected L2CA_Config request message. Invalid channel" \
73		" state, state=%d, lcid=%d\n", channel->state, channel->scid);
74		return EINVAL;
75	}
76
77	// Set requested channel configuration options
78	net_buffer* options = NULL;
79
80	if (channel->endpoint->fConfigurationSet) {
81		// Compare channel settings with defaults
82		if (channel->configuration->imtu != L2CAP_MTU_DEFAULT)
83			mtu = &channel->configuration->imtu;
84		if (channel->configuration->flush_timo != L2CAP_FLUSH_TIMO_DEFAULT)
85			flush_timo = &channel->configuration->flush_timo;
86		if (memcmp(&default_qos, &channel->configuration->oflow,
87			sizeof(channel->configuration->oflow)) != 0)
88			flow = &channel->configuration->oflow;
89
90			// Create configuration options
91			if (mtu != NULL || flush_timo != NULL || flow!=NULL)
92				options = l2cap_build_cfg_options(mtu, flush_timo, flow);
93
94			if (options == NULL)
95				return ENOBUFS;
96	}
97
98	// Send Configuration Request
99
100	// Create L2CAP command descriptor
101	channel->ident = btCoreData->ChannelAllocateIdent(conn);
102	if (channel->ident == L2CAP_NULL_IDENT)
103		return EIO;
104
105	net_buffer* buffer = l2cap_cfg_req(channel->ident, channel->dcid, 0, options);
106	if (buffer == NULL)
107		return ENOBUFS;
108
109	L2capFrame* command = btCoreData->SpawnSignal(conn, channel, buffer,
110		channel->ident, L2CAP_CFG_REQ);
111	if (command == NULL) {
112		gBufferModule->free(buffer);
113		channel->state = L2CAP_CHAN_CLOSED;
114		return ENOMEM;
115	}
116
117	channel->cfgState |= L2CAP_CFG_IN_SENT;
118
119	/* Adjust channel state for re-configuration */
120	if (channel->state == L2CAP_CHAN_OPEN) {
121		channel->state = L2CAP_CHAN_CONFIG;
122		channel->cfgState = 0;
123	}
124
125	flowf("Sending cfg req\n");
126	// Link command to the queue
127	SchedConnectionPurgeThread(channel->conn);
128
129	return B_OK;
130}
131
132
133status_t
134l2cap_cfg_rsp_ind(L2capChannel* channel)
135{
136	channel->cfgState |= L2CAP_CFG_OUT;
137	if ((channel->cfgState & L2CAP_CFG_BOTH) == L2CAP_CFG_BOTH) {
138		return channel->endpoint->MarkEstablished();
139	}
140
141	return B_OK;
142}
143
144
145status_t
146l2cap_cfg_req_ind(L2capChannel* channel)
147{
148	// if our configuration has not been yet sent ...
149	if (!(channel->cfgState & L2CAP_CFG_OUT_SENT)) {
150
151		// TODO: check if we can handle this conf
152
153		// send config_rsp
154		net_buffer* buf = l2cap_cfg_rsp(channel->ident, channel->dcid, 0,
155			L2CAP_SUCCESS, NULL);
156		L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf,
157			channel->ident, L2CAP_CFG_RSP);
158		if (cmd == NULL) {
159			gBufferModule->free(buf);
160			channel->state = L2CAP_CHAN_CLOSED;
161			return ENOMEM;
162		}
163
164		flowf("Sending cfg resp\n");
165		// Link command to the queue
166		SchedConnectionPurgeThread(channel->conn);
167
168		// set status
169		channel->cfgState |= L2CAP_CFG_OUT_SENT;
170
171	} else {
172
173
174	}
175
176
177	if ((channel->cfgState & L2CAP_CFG_BOTH) == L2CAP_CFG_BOTH) {
178		// Channel can be declared open
179		channel->endpoint->MarkEstablished();
180
181	} else if ((channel->cfgState & L2CAP_CFG_IN_SENT) == 0) {
182		// send configuration Request by our side
183		if (channel->endpoint->RequiresConfiguration()) {
184			// TODO: define complete configuration packet
185
186		} else {
187			// nothing special requested
188			channel->ident = btCoreData->ChannelAllocateIdent(channel->conn);
189			net_buffer* buf = l2cap_cfg_req(channel->ident, channel->dcid, 0, NULL);
190			L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf,
191				channel->ident, L2CAP_CFG_REQ);
192			if (cmd == NULL) {
193				gBufferModule->free(buf);
194				channel->state = L2CAP_CHAN_CLOSED;
195				return ENOMEM;
196			}
197
198			flowf("Sending cfg req\n");
199
200			// Link command to the queue
201			SchedConnectionPurgeThread(channel->conn);
202
203		}
204		channel->cfgState |= L2CAP_CFG_IN_SENT;
205	}
206
207	return B_OK;
208}
209
210
211status_t
212l2cap_discon_req_ind(L2capChannel* channel)
213{
214	return channel->endpoint->MarkClosed();
215}
216
217
218status_t
219l2cap_discon_rsp_ind(L2capChannel* channel)
220{
221	if (channel->state == L2CAP_CHAN_W4_L2CA_DISCON_RSP) {
222		channel->endpoint->MarkClosed();
223	}
224
225	return B_OK;
226}
227
228
229
230
231
232#if 0
233#pragma mark - Signals from Upper Layer
234#endif
235
236
237status_t
238l2cap_upper_con_req(L2capChannel* channel)
239{
240	channel->ident = btCoreData->ChannelAllocateIdent(channel->conn);
241
242	net_buffer* buf = l2cap_con_req(channel->ident, channel->psm, channel->scid);
243	L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf,
244		channel->ident, L2CAP_CON_REQ);
245
246	if (cmd == NULL) {
247		gBufferModule->free(buf);
248		return ENOMEM;
249	}
250
251	channel->state = L2CAP_CHAN_W4_L2CAP_CON_RSP;
252
253	// Link command to the queue
254	SchedConnectionPurgeThread(channel->conn);
255	return B_OK;
256}
257
258
259status_t
260l2cap_upper_dis_req(L2capChannel* channel)
261{
262	channel->ident = btCoreData->ChannelAllocateIdent(channel->conn);
263
264	net_buffer* buf = l2cap_discon_req(channel->ident, channel->dcid,
265		channel->scid);
266	L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf,
267		channel->ident, L2CAP_DISCON_REQ);
268	if (cmd == NULL) {
269		gBufferModule->free(buf);
270		return ENOMEM;
271	}
272
273	channel->state = L2CAP_CHAN_W4_L2CA_DISCON_RSP;
274
275	// Link command to the queue
276	SchedConnectionPurgeThread(channel->conn);
277	return B_OK;
278
279}
280
281
282#if 0
283#pragma mark -
284#endif
285
286
287status_t
288l2cap_co_receive(HciConnection* conn, net_buffer* buffer, uint16 dcid)
289{
290	debugf("Handle %d To dcid %x size=%ld\n", conn->handle, dcid, buffer->size);
291
292	L2capChannel* channel = btCoreData->ChannelBySourceID(conn, dcid);
293
294	if (channel == NULL) {
295		debugf("dcid %d does not exist for handle %d\n", dcid, conn->handle);
296		return B_ERROR;
297	}
298
299	if (channel->endpoint == NULL) {
300		debugf("dcid %d not bound to endpoint\n", dcid);
301		return B_ERROR;
302	}
303
304	return gStackModule->fifo_enqueue_buffer(
305		&channel->endpoint->fReceivingFifo, buffer);
306}
307
308
309status_t
310l2cap_cl_receive(HciConnection* conn, net_buffer* buffer, uint16 psm)
311{
312	L2capEndpoint* endpoint = L2capEndpoint::ForPsm(psm);
313
314	if (endpoint == NULL) {
315		debugf("no enpoint bound with psm %d\n", psm);
316		return B_ERROR;
317	}
318
319	flowf("Enqueue to fifo\n");
320	return gStackModule->fifo_enqueue_buffer(
321		&endpoint->fReceivingFifo, buffer);
322}
323
324
325
326