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#include <util/DoublyLinkedList.h>
7
8#include <KernelExport.h>
9
10#include <bluetooth/bluetooth.h>
11#include <bluetooth/bdaddrUtils.h>
12
13#include <btDebug.h>
14
15#include <l2cap.h>
16
17#include "ConnectionInterface.h"
18
19
20void PurgeChannels(HciConnection* conn);
21
22
23HciConnection::HciConnection()
24{
25	mutex_init(&fLock, "conn outgoing");
26	mutex_init(&fLockExpected, "frame expected");
27}
28
29
30HciConnection::~HciConnection()
31{
32	mutex_destroy(&fLock);
33	mutex_destroy(&fLockExpected);
34}
35
36
37HciConnection*
38AddConnection(uint16 handle, int type, const bdaddr_t& dst, hci_id hid)
39{
40	// Create connection descriptor
41
42	HciConnection* conn = ConnectionByHandle(handle, hid);
43	if (conn != NULL)
44		goto update;
45
46	conn = new (std::nothrow) HciConnection;
47	if (conn == NULL)
48		goto bail;
49
50	// memset(conn, 0, sizeof(HciConnection));
51
52	conn->currentRxPacket = NULL;
53	conn->currentRxExpectedLength = 0;
54update:
55	// fill values
56	bdaddrUtils::Copy(conn->destination, dst);
57	conn->type = type;
58	conn->handle = handle;
59	conn->Hid = hid;
60	conn->status = HCI_CONN_OPEN;
61	conn->mtu = L2CAP_MTU_MINIMUM; // TODO: give the mtu to the connection
62	conn->lastCid = L2CAP_FIRST_CID;
63	conn->lastIdent = L2CAP_FIRST_IDENT;
64
65	sConnectionList.Add(conn);
66
67bail:
68	return conn;
69}
70
71
72status_t
73RemoveConnection(const bdaddr_t& destination, hci_id hid)
74{
75	HciConnection*	conn;
76
77	DoublyLinkedList<HciConnection>::Iterator iterator
78		= sConnectionList.GetIterator();
79
80	while (iterator.HasNext()) {
81
82		conn = iterator.Next();
83		if (conn->Hid == hid
84			&& bdaddrUtils::Compare(conn->destination, destination)) {
85
86			// if the device is still part of the list, remove it
87			if (conn->GetDoublyLinkedListLink()->next != NULL
88				|| conn->GetDoublyLinkedListLink()->previous != NULL
89				|| conn == sConnectionList.Head()) {
90				sConnectionList.Remove(conn);
91
92				delete conn;
93				return B_OK;
94			}
95		}
96	}
97	return B_ERROR;
98}
99
100
101status_t
102RemoveConnection(uint16 handle, hci_id hid)
103{
104	HciConnection*	conn;
105
106	DoublyLinkedList<HciConnection>::Iterator iterator
107		= sConnectionList.GetIterator();
108	while (iterator.HasNext()) {
109
110		conn = iterator.Next();
111		if (conn->Hid == hid && conn->handle == handle) {
112
113			// if the device is still part of the list, remove it
114			if (conn->GetDoublyLinkedListLink()->next != NULL
115				|| conn->GetDoublyLinkedListLink()->previous != NULL
116				|| conn == sConnectionList.Head()) {
117				sConnectionList.Remove(conn);
118
119				PurgeChannels(conn);
120				delete conn;
121				return B_OK;
122			}
123		}
124	}
125	return B_ERROR;
126}
127
128
129hci_id
130RouteConnection(const bdaddr_t& destination) {
131
132	HciConnection* conn;
133
134	DoublyLinkedList<HciConnection>::Iterator iterator
135		= sConnectionList.GetIterator();
136	while (iterator.HasNext()) {
137
138		conn = iterator.Next();
139		if (bdaddrUtils::Compare(conn->destination, destination)) {
140			return conn->Hid;
141		}
142	}
143
144	return -1;
145}
146
147
148HciConnection*
149ConnectionByHandle(uint16 handle, hci_id hid)
150{
151	HciConnection*	conn;
152
153	DoublyLinkedList<HciConnection>::Iterator iterator
154		= sConnectionList.GetIterator();
155	while (iterator.HasNext()) {
156
157		conn = iterator.Next();
158		if (conn->Hid == hid && conn->handle == handle) {
159			return conn;
160		}
161	}
162
163	return NULL;
164}
165
166
167HciConnection*
168ConnectionByDestination(const bdaddr_t& destination, hci_id hid)
169{
170	HciConnection*	conn;
171
172	DoublyLinkedList<HciConnection>::Iterator iterator
173		= sConnectionList.GetIterator();
174	while (iterator.HasNext()) {
175
176		conn = iterator.Next();
177		if (conn->Hid == hid
178			&& bdaddrUtils::Compare(conn->destination, destination)) {
179			return conn;
180		}
181	}
182
183	return NULL;
184}
185
186
187#if 0
188#pragma mark - ACL helper funcs
189#endif
190
191void
192SetAclBuffer(HciConnection* conn, net_buffer* nbuf)
193{
194	conn->currentRxPacket = nbuf;
195}
196
197
198void
199SetAclExpectedSize(HciConnection* conn, size_t size)
200{
201	conn->currentRxExpectedLength = size;
202}
203
204
205void
206AclPutting(HciConnection* conn, size_t size)
207{
208	conn->currentRxExpectedLength -= size;
209}
210
211
212bool
213AclComplete(HciConnection* conn)
214{
215	return conn->currentRxExpectedLength == 0;
216}
217
218
219bool
220AclOverFlowed(HciConnection* conn)
221{
222	return conn->currentRxExpectedLength < 0;
223}
224
225
226#if 0
227#pragma mark - private funcs
228#endif
229
230void
231PurgeChannels(HciConnection* conn)
232{
233
234}
235