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 debugf("No endpoint bound for psm %d\n", 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 flowf("\n"); 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 && channel->state != L2CAP_CHAN_CONFIG) { 72 debugf("unexpected L2CA_Config request message. Invalid channel" \ 73 " state, state=%d, lcid=%d\n", channel->state, channel->scid); 74 return EINVAL; 75 } 76 77 // Set requested channel configuration options 78 net_buffer* options = NULL; 79 80 if (channel->endpoint->fConfigurationSet) { 81 // Compare channel settings with defaults 82 if (channel->configuration->imtu != L2CAP_MTU_DEFAULT) 83 mtu = &channel->configuration->imtu; 84 if (channel->configuration->flush_timo != L2CAP_FLUSH_TIMO_DEFAULT) 85 flush_timo = &channel->configuration->flush_timo; 86 if (memcmp(&default_qos, &channel->configuration->oflow, 87 sizeof(channel->configuration->oflow)) != 0) 88 flow = &channel->configuration->oflow; 89 90 // Create configuration options 91 if (mtu != NULL || flush_timo != NULL || flow!=NULL) 92 options = l2cap_build_cfg_options(mtu, flush_timo, flow); 93 94 if (options == NULL) 95 return ENOBUFS; 96 } 97 98 // Send Configuration Request 99 100 // Create L2CAP command descriptor 101 channel->ident = btCoreData->ChannelAllocateIdent(conn); 102 if (channel->ident == L2CAP_NULL_IDENT) 103 return EIO; 104 105 net_buffer* buffer = l2cap_cfg_req(channel->ident, channel->dcid, 0, options); 106 if (buffer == NULL) 107 return ENOBUFS; 108 109 L2capFrame* command = btCoreData->SpawnSignal(conn, channel, buffer, 110 channel->ident, L2CAP_CFG_REQ); 111 if (command == NULL) { 112 gBufferModule->free(buffer); 113 channel->state = L2CAP_CHAN_CLOSED; 114 return ENOMEM; 115 } 116 117 channel->cfgState |= L2CAP_CFG_IN_SENT; 118 119 /* Adjust channel state for re-configuration */ 120 if (channel->state == L2CAP_CHAN_OPEN) { 121 channel->state = L2CAP_CHAN_CONFIG; 122 channel->cfgState = 0; 123 } 124 125 flowf("Sending cfg req\n"); 126 // Link command to the queue 127 SchedConnectionPurgeThread(channel->conn); 128 129 return B_OK; 130} 131 132 133status_t 134l2cap_cfg_rsp_ind(L2capChannel* channel) 135{ 136 channel->cfgState |= L2CAP_CFG_OUT; 137 if ((channel->cfgState & L2CAP_CFG_BOTH) == L2CAP_CFG_BOTH) { 138 return channel->endpoint->MarkEstablished(); 139 } 140 141 return B_OK; 142} 143 144 145status_t 146l2cap_cfg_req_ind(L2capChannel* channel) 147{ 148 // if our configuration has not been yet sent ... 149 if (!(channel->cfgState & L2CAP_CFG_OUT_SENT)) { 150 151 // TODO: check if we can handle this conf 152 153 // send config_rsp 154 net_buffer* buf = l2cap_cfg_rsp(channel->ident, channel->dcid, 0, 155 L2CAP_SUCCESS, NULL); 156 L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf, 157 channel->ident, L2CAP_CFG_RSP); 158 if (cmd == NULL) { 159 gBufferModule->free(buf); 160 channel->state = L2CAP_CHAN_CLOSED; 161 return ENOMEM; 162 } 163 164 flowf("Sending cfg resp\n"); 165 // Link command to the queue 166 SchedConnectionPurgeThread(channel->conn); 167 168 // set status 169 channel->cfgState |= L2CAP_CFG_OUT_SENT; 170 171 } else { 172 173 174 } 175 176 177 if ((channel->cfgState & L2CAP_CFG_BOTH) == L2CAP_CFG_BOTH) { 178 // Channel can be declared open 179 channel->endpoint->MarkEstablished(); 180 181 } else if ((channel->cfgState & L2CAP_CFG_IN_SENT) == 0) { 182 // send configuration Request by our side 183 if (channel->endpoint->RequiresConfiguration()) { 184 // TODO: define complete configuration packet 185 186 } else { 187 // nothing special requested 188 channel->ident = btCoreData->ChannelAllocateIdent(channel->conn); 189 net_buffer* buf = l2cap_cfg_req(channel->ident, channel->dcid, 0, NULL); 190 L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf, 191 channel->ident, L2CAP_CFG_REQ); 192 if (cmd == NULL) { 193 gBufferModule->free(buf); 194 channel->state = L2CAP_CHAN_CLOSED; 195 return ENOMEM; 196 } 197 198 flowf("Sending cfg req\n"); 199 200 // Link command to the queue 201 SchedConnectionPurgeThread(channel->conn); 202 203 } 204 channel->cfgState |= L2CAP_CFG_IN_SENT; 205 } 206 207 return B_OK; 208} 209 210 211status_t 212l2cap_discon_req_ind(L2capChannel* channel) 213{ 214 return channel->endpoint->MarkClosed(); 215} 216 217 218status_t 219l2cap_discon_rsp_ind(L2capChannel* channel) 220{ 221 if (channel->state == L2CAP_CHAN_W4_L2CA_DISCON_RSP) { 222 channel->endpoint->MarkClosed(); 223 } 224 225 return B_OK; 226} 227 228 229 230 231 232#if 0 233#pragma mark - Signals from Upper Layer 234#endif 235 236 237status_t 238l2cap_upper_con_req(L2capChannel* channel) 239{ 240 channel->ident = btCoreData->ChannelAllocateIdent(channel->conn); 241 242 net_buffer* buf = l2cap_con_req(channel->ident, channel->psm, channel->scid); 243 L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf, 244 channel->ident, L2CAP_CON_REQ); 245 246 if (cmd == NULL) { 247 gBufferModule->free(buf); 248 return ENOMEM; 249 } 250 251 channel->state = L2CAP_CHAN_W4_L2CAP_CON_RSP; 252 253 // Link command to the queue 254 SchedConnectionPurgeThread(channel->conn); 255 return B_OK; 256} 257 258 259status_t 260l2cap_upper_dis_req(L2capChannel* channel) 261{ 262 channel->ident = btCoreData->ChannelAllocateIdent(channel->conn); 263 264 net_buffer* buf = l2cap_discon_req(channel->ident, channel->dcid, 265 channel->scid); 266 L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf, 267 channel->ident, L2CAP_DISCON_REQ); 268 if (cmd == NULL) { 269 gBufferModule->free(buf); 270 return ENOMEM; 271 } 272 273 channel->state = L2CAP_CHAN_W4_L2CA_DISCON_RSP; 274 275 // Link command to the queue 276 SchedConnectionPurgeThread(channel->conn); 277 return B_OK; 278 279} 280 281 282#if 0 283#pragma mark - 284#endif 285 286 287status_t 288l2cap_co_receive(HciConnection* conn, net_buffer* buffer, uint16 dcid) 289{ 290 debugf("Handle %d To dcid %x size=%ld\n", conn->handle, dcid, buffer->size); 291 292 L2capChannel* channel = btCoreData->ChannelBySourceID(conn, dcid); 293 294 if (channel == NULL) { 295 debugf("dcid %d does not exist for handle %d\n", dcid, conn->handle); 296 return B_ERROR; 297 } 298 299 if (channel->endpoint == NULL) { 300 debugf("dcid %d not bound to endpoint\n", dcid); 301 return B_ERROR; 302 } 303 304 return gStackModule->fifo_enqueue_buffer( 305 &channel->endpoint->fReceivingFifo, buffer); 306} 307 308 309status_t 310l2cap_cl_receive(HciConnection* conn, net_buffer* buffer, uint16 psm) 311{ 312 L2capEndpoint* endpoint = L2capEndpoint::ForPsm(psm); 313 314 if (endpoint == NULL) { 315 debugf("no enpoint bound with psm %d\n", psm); 316 return B_ERROR; 317 } 318 319 flowf("Enqueue to fifo\n"); 320 return gStackModule->fifo_enqueue_buffer( 321 &endpoint->fReceivingFifo, buffer); 322} 323 324 325 326