xref: /haiku/src/add-ons/kernel/bluetooth/btCoreData/ConnectionInterface.cpp (revision 13581b3d2a71545960b98fefebc5225b5bf29072)
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 
22 struct net_protocol_module_info* L2cap = NULL;
23 extern net_buffer_module_info* gBufferModule;
24 
25 
26 HciConnection::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 
41 HciConnection::~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 
63 HciConnection*
64 AddConnection(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;
80 update:
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 
99 bail:
100 	return conn;
101 }
102 
103 
104 status_t
105 RemoveConnection(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 
135 status_t
136 RemoveConnection(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 
164 hci_id
165 RouteConnection(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 
184 HciConnection*
185 ConnectionByHandle(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 
204 HciConnection*
205 ConnectionByDestination(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 
224 uint8
225 allocate_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 
249 void*
250 lookup_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 
262 void
263 free_command_ident(HciConnection* conn, uint8 ident)
264 {
265 	MutexLocker _(&conn->fLock);
266 	conn->fInUseIdents.Remove(ident);
267 }
268