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