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#include <KernelExport.h> 6#include <NetBufferUtilities.h> 7 8#include "l2cap_internal.h" 9#include "l2cap_signal.h" 10#include "l2cap_command.h" 11#include "l2cap_lower.h" 12 13#include "L2capEndpoint.h" 14 15#define BT_DEBUG_THIS_MODULE 16#define SUBMODULE_NAME "upper" 17#define SUBMODULE_COLOR 36 18#include <btDebug.h> 19#include <l2cap.h> 20 21 22#if 0 23#pragma mark - Signals from the other pair 24#endif 25 26 27status_t 28l2cap_l2ca_con_ind(L2capChannel* channel) 29{ 30 L2capEndpoint* endpoint = L2capEndpoint::ForPsm(channel->psm); 31 32 if (endpoint == NULL) { // TODO: refuse connection no endpoint bound 33 ERROR("%s: No endpoint bound for psm %d\n", __func__, channel->psm); 34 return B_ERROR; 35 } 36 37 // Pair Channel with endpoint 38 endpoint->BindNewEnpointToChannel(channel); 39 40 net_buffer* buf = l2cap_con_rsp(channel->ident, channel->scid, channel->dcid, 41 L2CAP_SUCCESS, L2CAP_NO_INFO); 42 L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf, 43 channel->ident, L2CAP_CON_RSP); 44 if (cmd == NULL) { 45 gBufferModule->free(buf); 46 return ENOMEM; 47 } 48 49 // we can move to configuration... 50 channel->state = L2CAP_CHAN_CONFIG; 51 52 // Link command to the queue 53 SchedConnectionPurgeThread(channel->conn); 54 return B_OK; 55} 56 57 58status_t 59l2cap_con_rsp_ind(HciConnection* conn, L2capChannel* channel) 60{ 61 uint16* flush_timo = NULL; 62 uint16* mtu = NULL; 63 l2cap_flow_t* flow = NULL; 64 65 CALLED(); 66 67 // We received a configuration response, connection process 68 // is a step further but still configuration pending 69 70 // Check channel state 71 if (channel->state != L2CAP_CHAN_OPEN 72 && channel->state != L2CAP_CHAN_CONFIG) { 73 ERROR("%s: unexpected L2CA_Config request message. Invalid channel" 74 " state, state=%d, lcid=%d\n", __func__, channel->state, channel->scid); 75 return EINVAL; 76 } 77 78 // Set requested channel configuration options 79 net_buffer* options = NULL; 80 81 if (channel->endpoint->fConfigurationSet) { 82 // Compare channel settings with defaults 83 if (channel->configuration->imtu != L2CAP_MTU_DEFAULT) 84 mtu = &channel->configuration->imtu; 85 if (channel->configuration->flush_timo != L2CAP_FLUSH_TIMO_DEFAULT) 86 flush_timo = &channel->configuration->flush_timo; 87 if (memcmp(&default_qos, &channel->configuration->oflow, 88 sizeof(channel->configuration->oflow)) != 0) 89 flow = &channel->configuration->oflow; 90 91 // Create configuration options 92 if (mtu != NULL || flush_timo != NULL || flow!=NULL) 93 options = l2cap_build_cfg_options(mtu, flush_timo, flow); 94 95 if (options == NULL) 96 return ENOBUFS; 97 } 98 99 // Send Configuration Request 100 101 // Create L2CAP command descriptor 102 channel->ident = btCoreData->ChannelAllocateIdent(conn); 103 if (channel->ident == L2CAP_NULL_IDENT) 104 return EIO; 105 106 net_buffer* buffer = l2cap_cfg_req(channel->ident, channel->dcid, 0, options); 107 if (buffer == NULL) 108 return ENOBUFS; 109 110 L2capFrame* command = btCoreData->SpawnSignal(conn, channel, buffer, 111 channel->ident, L2CAP_CFG_REQ); 112 if (command == NULL) { 113 gBufferModule->free(buffer); 114 channel->state = L2CAP_CHAN_CLOSED; 115 return ENOMEM; 116 } 117 118 channel->cfgState |= L2CAP_CFG_IN_SENT; 119 120 /* Adjust channel state for re-configuration */ 121 if (channel->state == L2CAP_CHAN_OPEN) { 122 channel->state = L2CAP_CHAN_CONFIG; 123 channel->cfgState = 0; 124 } 125 126 TRACE("%s: Sending cfg req\n", __func__); 127 // Link command to the queue 128 SchedConnectionPurgeThread(channel->conn); 129 130 return B_OK; 131} 132 133 134status_t 135l2cap_cfg_rsp_ind(L2capChannel* channel) 136{ 137 channel->cfgState |= L2CAP_CFG_OUT; 138 if ((channel->cfgState & L2CAP_CFG_BOTH) == L2CAP_CFG_BOTH) { 139 return channel->endpoint->MarkEstablished(); 140 } 141 142 return B_OK; 143} 144 145 146status_t 147l2cap_cfg_req_ind(L2capChannel* channel) 148{ 149 // if our configuration has not been yet sent ... 150 if (!(channel->cfgState & L2CAP_CFG_OUT_SENT)) { 151 152 // TODO: check if we can handle this conf 153 154 // send config_rsp 155 net_buffer* buf = l2cap_cfg_rsp(channel->ident, channel->dcid, 0, 156 L2CAP_SUCCESS, NULL); 157 L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf, 158 channel->ident, L2CAP_CFG_RSP); 159 if (cmd == NULL) { 160 gBufferModule->free(buf); 161 channel->state = L2CAP_CHAN_CLOSED; 162 return ENOMEM; 163 } 164 165 // Link command to the queue 166 SchedConnectionPurgeThread(channel->conn); 167 168 // set status 169 channel->cfgState |= L2CAP_CFG_OUT_SENT; 170 171 } 172 173 if ((channel->cfgState & L2CAP_CFG_BOTH) == L2CAP_CFG_BOTH) { 174 // Channel can be declared open 175 channel->endpoint->MarkEstablished(); 176 177 } else if ((channel->cfgState & L2CAP_CFG_IN_SENT) == 0) { 178 // send configuration Request by our side 179 if (channel->endpoint->RequiresConfiguration()) { 180 // TODO: define complete configuration packet 181 182 } else { 183 // nothing special requested 184 channel->ident = btCoreData->ChannelAllocateIdent(channel->conn); 185 net_buffer* buf = l2cap_cfg_req(channel->ident, channel->dcid, 0, NULL); 186 L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf, 187 channel->ident, L2CAP_CFG_REQ); 188 if (cmd == NULL) { 189 gBufferModule->free(buf); 190 channel->state = L2CAP_CHAN_CLOSED; 191 return ENOMEM; 192 } 193 194 // Link command to the queue 195 SchedConnectionPurgeThread(channel->conn); 196 197 } 198 channel->cfgState |= L2CAP_CFG_IN_SENT; 199 } 200 201 return B_OK; 202} 203 204 205status_t 206l2cap_discon_req_ind(L2capChannel* channel) 207{ 208 return channel->endpoint->MarkClosed(); 209} 210 211 212status_t 213l2cap_discon_rsp_ind(L2capChannel* channel) 214{ 215 if (channel->state == L2CAP_CHAN_W4_L2CA_DISCON_RSP) { 216 channel->endpoint->MarkClosed(); 217 } 218 219 return B_OK; 220} 221 222 223 224 225 226#if 0 227#pragma mark - Signals from Upper Layer 228#endif 229 230 231status_t 232l2cap_upper_con_req(L2capChannel* channel) 233{ 234 channel->ident = btCoreData->ChannelAllocateIdent(channel->conn); 235 236 net_buffer* buf = l2cap_con_req(channel->ident, channel->psm, channel->scid); 237 L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf, 238 channel->ident, L2CAP_CON_REQ); 239 240 if (cmd == NULL) { 241 gBufferModule->free(buf); 242 return ENOMEM; 243 } 244 245 channel->state = L2CAP_CHAN_W4_L2CAP_CON_RSP; 246 247 // Link command to the queue 248 SchedConnectionPurgeThread(channel->conn); 249 return B_OK; 250} 251 252 253status_t 254l2cap_upper_dis_req(L2capChannel* channel) 255{ 256 channel->ident = btCoreData->ChannelAllocateIdent(channel->conn); 257 258 net_buffer* buf = l2cap_discon_req(channel->ident, channel->dcid, 259 channel->scid); 260 L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf, 261 channel->ident, L2CAP_DISCON_REQ); 262 if (cmd == NULL) { 263 gBufferModule->free(buf); 264 return ENOMEM; 265 } 266 267 channel->state = L2CAP_CHAN_W4_L2CA_DISCON_RSP; 268 269 // Link command to the queue 270 SchedConnectionPurgeThread(channel->conn); 271 return B_OK; 272 273} 274 275 276#if 0 277#pragma mark - 278#endif 279 280 281status_t 282l2cap_co_receive(HciConnection* conn, net_buffer* buffer, uint16 dcid) 283{ 284 CALLED(); 285 286 L2capChannel* channel = btCoreData->ChannelBySourceID(conn, dcid); 287 288 if (channel == NULL) { 289 ERROR("%s: dcid %d does not exist for handle %d\n", __func__, 290 dcid, conn->handle); 291 return B_ERROR; 292 } 293 294 if (channel->endpoint == NULL) { 295 ERROR("%s: dcid %d not bound to endpoint\n", __func__, dcid); 296 return B_ERROR; 297 } 298 299 return gStackModule->fifo_enqueue_buffer( 300 &channel->endpoint->fReceivingFifo, buffer); 301} 302 303 304status_t 305l2cap_cl_receive(HciConnection* conn, net_buffer* buffer, uint16 psm) 306{ 307 L2capEndpoint* endpoint = L2capEndpoint::ForPsm(psm); 308 309 if (endpoint == NULL) { 310 ERROR("%s: no endpoint bound with psm %d\n", __func__, psm); 311 return B_ERROR; 312 } 313 314 return gStackModule->fifo_enqueue_buffer( 315 &endpoint->fReceivingFifo, buffer); 316} 317 318 319 320