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#include <util/AutoLock.h>
8
9#include <net_protocol.h>
10
11#include <bluetooth/bluetooth.h>
12#include <bluetooth/bdaddrUtils.h>
13#include <bluetooth/L2CAP/btL2CAP.h>
14
15#include <btDebug.h>
16#include <btModules.h>
17
18#include <l2cap.h>
19
20#include "ConnectionInterface.h"
21
22struct net_protocol_module_info* L2cap = NULL;
23extern net_buffer_module_info* gBufferModule;
24
25
26HciConnection::HciConnection(hci_id hid)
27{
28	mutex_init(&fLock, "HciConnection");
29	Hid = hid;
30	fNextIdent = L2CAP_FIRST_CID;
31
32	// TODO: This doesn't really belong here...
33	interface_address = {};
34	address_dl = {};
35	interface_address.local = (struct sockaddr*)&address_dl;
36	interface_address.destination = (struct sockaddr*)&address_dest;
37	address_dl.sdl_index = Hid;
38}
39
40
41HciConnection::~HciConnection()
42{
43	if (L2cap == NULL)
44	if (get_module(NET_BLUETOOTH_L2CAP_NAME, (module_info**)&L2cap) != B_OK) {
45		ERROR("%s: cannot get module \"%s\"\n", __func__,
46			NET_BLUETOOTH_L2CAP_NAME);
47	} // TODO: someone put it
48
49	// Inform the L2CAP module this connection is about to be gone.
50	if (L2cap != NULL) {
51		net_buffer* error = gBufferModule->create(128);
52		error->interface_address = &interface_address;
53		if (L2cap->error_received(B_NET_ERROR_UNREACH_HOST, error) != B_OK) {
54			error->interface_address = NULL;
55			gBufferModule->free(error);
56		}
57	}
58
59	mutex_destroy(&fLock);
60}
61
62
63HciConnection*
64AddConnection(uint16 handle, int type, const bdaddr_t& dst, hci_id hid)
65{
66	// Create connection descriptor
67
68	HciConnection* conn = ConnectionByHandle(handle, hid);
69	if (conn != NULL)
70		goto update;
71
72	conn = new (std::nothrow) HciConnection(hid);
73	if (conn == NULL)
74		goto bail;
75
76	// memset(conn, 0, sizeof(HciConnection));
77
78	conn->currentRxPacket = NULL;
79	conn->currentRxExpectedLength = 0;
80update:
81	// fill values
82	bdaddrUtils::Copy(conn->destination, dst);
83	{
84	sockaddr_l2cap* destination = (sockaddr_l2cap*)&conn->address_dest;
85	destination->l2cap_len = sizeof(sockaddr_l2cap);
86	destination->l2cap_family = AF_BLUETOOTH;
87	destination->l2cap_bdaddr = dst;
88	}
89	conn->type = type;
90	conn->handle = handle;
91	conn->status = HCI_CONN_OPEN;
92	conn->mtu = L2CAP_MTU_MINIMUM; // TODO: give the mtu to the connection
93
94	{
95	MutexLocker _(&sConnectionListLock);
96	sConnectionList.Add(conn);
97	}
98
99bail:
100	return conn;
101}
102
103
104status_t
105RemoveConnection(const bdaddr_t& destination, hci_id hid)
106{
107	MutexLocker locker(&sConnectionListLock);
108	HciConnection*	conn;
109
110	DoublyLinkedList<HciConnection>::Iterator iterator
111		= sConnectionList.GetIterator();
112
113	while (iterator.HasNext()) {
114
115		conn = iterator.Next();
116		if (conn->Hid == hid
117			&& bdaddrUtils::Compare(conn->destination, destination)) {
118
119			// if the device is still part of the list, remove it
120			if (conn->GetDoublyLinkedListLink()->next != NULL
121				|| conn->GetDoublyLinkedListLink()->previous != NULL
122				|| conn == sConnectionList.Head()) {
123				sConnectionList.Remove(conn);
124
125				locker.Unlock();
126				delete conn;
127				return B_OK;
128			}
129		}
130	}
131	return B_ERROR;
132}
133
134
135status_t
136RemoveConnection(uint16 handle, hci_id hid)
137{
138	MutexLocker locker(&sConnectionListLock);
139	HciConnection*	conn;
140
141	DoublyLinkedList<HciConnection>::Iterator iterator
142		= sConnectionList.GetIterator();
143	while (iterator.HasNext()) {
144
145		conn = iterator.Next();
146		if (conn->Hid == hid && conn->handle == handle) {
147
148			// if the device is still part of the list, remove it
149			if (conn->GetDoublyLinkedListLink()->next != NULL
150				|| conn->GetDoublyLinkedListLink()->previous != NULL
151				|| conn == sConnectionList.Head()) {
152				sConnectionList.Remove(conn);
153
154				locker.Unlock();
155				delete conn;
156				return B_OK;
157			}
158		}
159	}
160	return B_ERROR;
161}
162
163
164hci_id
165RouteConnection(const bdaddr_t& destination)
166{
167	MutexLocker _(&sConnectionListLock);
168	HciConnection* conn;
169
170	DoublyLinkedList<HciConnection>::Iterator iterator
171		= sConnectionList.GetIterator();
172	while (iterator.HasNext()) {
173
174		conn = iterator.Next();
175		if (bdaddrUtils::Compare(conn->destination, destination)) {
176			return conn->Hid;
177		}
178	}
179
180	return -1;
181}
182
183
184HciConnection*
185ConnectionByHandle(uint16 handle, hci_id hid)
186{
187	MutexLocker _(&sConnectionListLock);
188	HciConnection*	conn;
189
190	DoublyLinkedList<HciConnection>::Iterator iterator
191		= sConnectionList.GetIterator();
192	while (iterator.HasNext()) {
193
194		conn = iterator.Next();
195		if (conn->Hid == hid && conn->handle == handle) {
196			return conn;
197		}
198	}
199
200	return NULL;
201}
202
203
204HciConnection*
205ConnectionByDestination(const bdaddr_t& destination, hci_id hid)
206{
207	MutexLocker _(&sConnectionListLock);
208
209	DoublyLinkedList<HciConnection>::Iterator iterator
210		= sConnectionList.GetIterator();
211	while (iterator.HasNext()) {
212
213		HciConnection* conn = iterator.Next();
214		if (conn->Hid == hid
215			&& bdaddrUtils::Compare(conn->destination, destination)) {
216			return conn;
217		}
218	}
219
220	return NULL;
221}
222
223
224uint8
225allocate_command_ident(HciConnection* conn, void* pointer)
226{
227	MutexLocker _(&conn->fLock);
228
229	uint8 ident = conn->fNextIdent + 1;
230
231	if (ident < L2CAP_FIRST_IDENT)
232		ident = L2CAP_FIRST_IDENT;
233
234	while (ident != conn->fNextIdent) {
235		if (conn->fInUseIdents.Find(ident) == conn->fInUseIdents.End()) {
236			conn->fInUseIdents.Insert(ident, pointer);
237			return ident;
238		}
239
240		ident++;
241		if (ident < L2CAP_FIRST_IDENT)
242			ident = L2CAP_FIRST_IDENT;
243	}
244
245	return L2CAP_NULL_IDENT;
246}
247
248
249void*
250lookup_command_ident(HciConnection* conn, uint8 ident)
251{
252	MutexLocker _(&conn->fLock);
253
254	auto iter = conn->fInUseIdents.Find(ident);
255	if (iter == conn->fInUseIdents.End())
256		return NULL;
257
258	return iter->Value();
259}
260
261
262void
263free_command_ident(HciConnection* conn, uint8 ident)
264{
265	MutexLocker _(&conn->fLock);
266	conn->fInUseIdents.Remove(ident);
267}
268