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 12 L2capEndpointManager gL2capEndpointManager; 13 14 15 L2capEndpointManager::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 24 L2capEndpointManager::~L2capEndpointManager() 25 { 26 rw_lock_destroy(&fBoundEndpointsLock); 27 rw_lock_destroy(&fChannelEndpointsLock); 28 } 29 30 31 status_t 32 L2capEndpointManager::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 55 status_t 56 L2capEndpointManager::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 68 L2capEndpoint* 69 L2capEndpointManager::ForPSM(uint16 psm) 70 { 71 ReadLocker _(fBoundEndpointsLock); 72 // TODO: Acquire reference? 73 return fBoundEndpoints.Find(psm); 74 } 75 76 77 status_t 78 L2capEndpointManager::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 101 status_t 102 L2capEndpointManager::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 114 L2capEndpoint* 115 L2capEndpointManager::ForChannel(uint16 cid) 116 { 117 ReadLocker _(fChannelEndpointsLock); 118 // TODO: Acquire reference? 119 return fChannelEndpoints.Find(cid); 120 } 121 122 123 void 124 L2capEndpointManager::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