1/* 2 * Copyright 2024, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5#include "L2capEndpointManager.h" 6 7#include <AutoDeleter.h> 8 9#include <bluetooth/bdaddrUtils.h> 10 11 12L2capEndpointManager gL2capEndpointManager; 13 14 15L2capEndpointManager::L2capEndpointManager() 16 : 17 fNextChannelID(L2CAP_FIRST_CID) 18{ 19 rw_lock_init(&fBoundEndpointsLock, "l2cap bound endpoints"); 20 rw_lock_init(&fChannelEndpointsLock, "l2cap channel endpoints"); 21} 22 23 24L2capEndpointManager::~L2capEndpointManager() 25{ 26 rw_lock_destroy(&fBoundEndpointsLock); 27 rw_lock_destroy(&fChannelEndpointsLock); 28} 29 30 31status_t 32L2capEndpointManager::Bind(L2capEndpoint* endpoint, const sockaddr_l2cap& address) 33{ 34 // TODO: Support binding to specific addresses? 35 if (!Bluetooth::bdaddrUtils::Compare(address.l2cap_bdaddr, BDADDR_ANY)) 36 return EINVAL; 37 38 // PSM values must be odd. 39 if ((address.l2cap_psm & 1) == 0) 40 return EINVAL; 41 42 WriteLocker _(fBoundEndpointsLock); 43 44 if (fBoundEndpoints.Find(address.l2cap_psm) != NULL) 45 return EADDRINUSE; 46 47 memcpy(*endpoint->LocalAddress(), &address, sizeof(struct sockaddr_l2cap)); 48 fBoundEndpoints.Insert(endpoint); 49 gSocketModule->acquire_socket(endpoint->socket); 50 51 return B_OK; 52} 53 54 55status_t 56L2capEndpointManager::Unbind(L2capEndpoint* endpoint) 57{ 58 WriteLocker _(fBoundEndpointsLock); 59 60 fBoundEndpoints.Remove(endpoint); 61 (*endpoint->LocalAddress())->sa_len = 0; 62 gSocketModule->release_socket(endpoint->socket); 63 64 return B_OK; 65} 66 67 68L2capEndpoint* 69L2capEndpointManager::ForPSM(uint16 psm) 70{ 71 ReadLocker _(fBoundEndpointsLock); 72 // TODO: Acquire reference? 73 return fBoundEndpoints.Find(psm); 74} 75 76 77status_t 78L2capEndpointManager::BindToChannel(L2capEndpoint* endpoint) 79{ 80 WriteLocker _(fChannelEndpointsLock); 81 82 for (uint16 i = 0; i < (L2CAP_LAST_CID - L2CAP_FIRST_CID); i++) { 83 const uint16 cid = fNextChannelID; 84 fNextChannelID++; 85 if (fNextChannelID < L2CAP_FIRST_CID) 86 fNextChannelID = L2CAP_FIRST_CID; 87 88 if (fChannelEndpoints.Find(cid) != NULL) 89 continue; 90 91 endpoint->fChannelID = cid; 92 fChannelEndpoints.Insert(endpoint); 93 gSocketModule->acquire_socket(endpoint->socket); 94 return B_OK; 95 } 96 97 return EADDRINUSE; 98} 99 100 101status_t 102L2capEndpointManager::UnbindFromChannel(L2capEndpoint* endpoint) 103{ 104 WriteLocker _(fChannelEndpointsLock); 105 106 fChannelEndpoints.Remove(endpoint); 107 endpoint->fChannelID = 0; 108 gSocketModule->release_socket(endpoint->socket); 109 110 return B_OK; 111} 112 113 114L2capEndpoint* 115L2capEndpointManager::ForChannel(uint16 cid) 116{ 117 ReadLocker _(fChannelEndpointsLock); 118 // TODO: Acquire reference? 119 return fChannelEndpoints.Find(cid); 120} 121 122 123void 124L2capEndpointManager::Disconnected(HciConnection* connection) 125{ 126 ReadLocker _(fChannelEndpointsLock); 127 auto iter = fChannelEndpoints.GetIterator(); 128 while (iter.HasNext()) { 129 L2capEndpoint* endpoint = iter.Next(); 130 if (endpoint->fConnection != connection) 131 continue; 132 133 endpoint->fConnection = NULL; 134 endpoint->fState = L2capEndpoint::CLOSED; 135 } 136} 137 138