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		ERROR("%s: No endpoint bound for psm %d\n", __func__, 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	CALLED();
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
72		&& channel->state != L2CAP_CHAN_CONFIG) {
73		ERROR("%s: unexpected L2CA_Config request message. Invalid channel"
74			" state, state=%d, lcid=%d\n", __func__, channel->state, channel->scid);
75		return EINVAL;
76	}
77
78	// Set requested channel configuration options
79	net_buffer* options = NULL;
80
81	if (channel->endpoint->fConfigurationSet) {
82		// Compare channel settings with defaults
83		if (channel->configuration->imtu != L2CAP_MTU_DEFAULT)
84			mtu = &channel->configuration->imtu;
85		if (channel->configuration->flush_timo != L2CAP_FLUSH_TIMO_DEFAULT)
86			flush_timo = &channel->configuration->flush_timo;
87		if (memcmp(&default_qos, &channel->configuration->oflow,
88			sizeof(channel->configuration->oflow)) != 0)
89			flow = &channel->configuration->oflow;
90
91			// Create configuration options
92			if (mtu != NULL || flush_timo != NULL || flow!=NULL)
93				options = l2cap_build_cfg_options(mtu, flush_timo, flow);
94
95			if (options == NULL)
96				return ENOBUFS;
97	}
98
99	// Send Configuration Request
100
101	// Create L2CAP command descriptor
102	channel->ident = btCoreData->ChannelAllocateIdent(conn);
103	if (channel->ident == L2CAP_NULL_IDENT)
104		return EIO;
105
106	net_buffer* buffer = l2cap_cfg_req(channel->ident, channel->dcid, 0, options);
107	if (buffer == NULL)
108		return ENOBUFS;
109
110	L2capFrame* command = btCoreData->SpawnSignal(conn, channel, buffer,
111		channel->ident, L2CAP_CFG_REQ);
112	if (command == NULL) {
113		gBufferModule->free(buffer);
114		channel->state = L2CAP_CHAN_CLOSED;
115		return ENOMEM;
116	}
117
118	channel->cfgState |= L2CAP_CFG_IN_SENT;
119
120	/* Adjust channel state for re-configuration */
121	if (channel->state == L2CAP_CHAN_OPEN) {
122		channel->state = L2CAP_CHAN_CONFIG;
123		channel->cfgState = 0;
124	}
125
126	TRACE("%s: Sending cfg req\n", __func__);
127	// Link command to the queue
128	SchedConnectionPurgeThread(channel->conn);
129
130	return B_OK;
131}
132
133
134status_t
135l2cap_cfg_rsp_ind(L2capChannel* channel)
136{
137	channel->cfgState |= L2CAP_CFG_OUT;
138	if ((channel->cfgState & L2CAP_CFG_BOTH) == L2CAP_CFG_BOTH) {
139		return channel->endpoint->MarkEstablished();
140	}
141
142	return B_OK;
143}
144
145
146status_t
147l2cap_cfg_req_ind(L2capChannel* channel)
148{
149	// if our configuration has not been yet sent ...
150	if (!(channel->cfgState & L2CAP_CFG_OUT_SENT)) {
151
152		// TODO: check if we can handle this conf
153
154		// send config_rsp
155		net_buffer* buf = l2cap_cfg_rsp(channel->ident, channel->dcid, 0,
156			L2CAP_SUCCESS, NULL);
157		L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf,
158			channel->ident, L2CAP_CFG_RSP);
159		if (cmd == NULL) {
160			gBufferModule->free(buf);
161			channel->state = L2CAP_CHAN_CLOSED;
162			return ENOMEM;
163		}
164
165		// Link command to the queue
166		SchedConnectionPurgeThread(channel->conn);
167
168		// set status
169		channel->cfgState |= L2CAP_CFG_OUT_SENT;
170
171	}
172
173	if ((channel->cfgState & L2CAP_CFG_BOTH) == L2CAP_CFG_BOTH) {
174		// Channel can be declared open
175		channel->endpoint->MarkEstablished();
176
177	} else if ((channel->cfgState & L2CAP_CFG_IN_SENT) == 0) {
178		// send configuration Request by our side
179		if (channel->endpoint->RequiresConfiguration()) {
180			// TODO: define complete configuration packet
181
182		} else {
183			// nothing special requested
184			channel->ident = btCoreData->ChannelAllocateIdent(channel->conn);
185			net_buffer* buf = l2cap_cfg_req(channel->ident, channel->dcid, 0, NULL);
186			L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf,
187				channel->ident, L2CAP_CFG_REQ);
188			if (cmd == NULL) {
189				gBufferModule->free(buf);
190				channel->state = L2CAP_CHAN_CLOSED;
191				return ENOMEM;
192			}
193
194			// Link command to the queue
195			SchedConnectionPurgeThread(channel->conn);
196
197		}
198		channel->cfgState |= L2CAP_CFG_IN_SENT;
199	}
200
201	return B_OK;
202}
203
204
205status_t
206l2cap_discon_req_ind(L2capChannel* channel)
207{
208	return channel->endpoint->MarkClosed();
209}
210
211
212status_t
213l2cap_discon_rsp_ind(L2capChannel* channel)
214{
215	if (channel->state == L2CAP_CHAN_W4_L2CA_DISCON_RSP) {
216		channel->endpoint->MarkClosed();
217	}
218
219	return B_OK;
220}
221
222
223
224
225
226#if 0
227#pragma mark - Signals from Upper Layer
228#endif
229
230
231status_t
232l2cap_upper_con_req(L2capChannel* channel)
233{
234	channel->ident = btCoreData->ChannelAllocateIdent(channel->conn);
235
236	net_buffer* buf = l2cap_con_req(channel->ident, channel->psm, channel->scid);
237	L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf,
238		channel->ident, L2CAP_CON_REQ);
239
240	if (cmd == NULL) {
241		gBufferModule->free(buf);
242		return ENOMEM;
243	}
244
245	channel->state = L2CAP_CHAN_W4_L2CAP_CON_RSP;
246
247	// Link command to the queue
248	SchedConnectionPurgeThread(channel->conn);
249	return B_OK;
250}
251
252
253status_t
254l2cap_upper_dis_req(L2capChannel* channel)
255{
256	channel->ident = btCoreData->ChannelAllocateIdent(channel->conn);
257
258	net_buffer* buf = l2cap_discon_req(channel->ident, channel->dcid,
259		channel->scid);
260	L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf,
261		channel->ident, L2CAP_DISCON_REQ);
262	if (cmd == NULL) {
263		gBufferModule->free(buf);
264		return ENOMEM;
265	}
266
267	channel->state = L2CAP_CHAN_W4_L2CA_DISCON_RSP;
268
269	// Link command to the queue
270	SchedConnectionPurgeThread(channel->conn);
271	return B_OK;
272
273}
274
275
276#if 0
277#pragma mark -
278#endif
279
280
281status_t
282l2cap_co_receive(HciConnection* conn, net_buffer* buffer, uint16 dcid)
283{
284	CALLED();
285
286	L2capChannel* channel = btCoreData->ChannelBySourceID(conn, dcid);
287
288	if (channel == NULL) {
289		ERROR("%s: dcid %d does not exist for handle %d\n", __func__,
290			dcid, conn->handle);
291		return B_ERROR;
292	}
293
294	if (channel->endpoint == NULL) {
295		ERROR("%s: dcid %d not bound to endpoint\n", __func__, dcid);
296		return B_ERROR;
297	}
298
299	return gStackModule->fifo_enqueue_buffer(
300		&channel->endpoint->fReceivingFifo, buffer);
301}
302
303
304status_t
305l2cap_cl_receive(HciConnection* conn, net_buffer* buffer, uint16 psm)
306{
307	L2capEndpoint* endpoint = L2capEndpoint::ForPsm(psm);
308
309	if (endpoint == NULL) {
310		ERROR("%s: no endpoint bound with psm %d\n", __func__, psm);
311		return B_ERROR;
312	}
313
314	return gStackModule->fifo_enqueue_buffer(
315		&endpoint->fReceivingFifo, buffer);
316}
317
318
319
320