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/*- 7 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18*/ 19#include <KernelExport.h> 20#include <string.h> 21#include <lock.h> 22 23#include <NetBufferUtilities.h> 24 25#include <bluetooth/HCI/btHCI_transport.h> 26 27#include <btModules.h> 28#include <l2cap.h> 29 30#include "l2cap_internal.h" 31#include "l2cap_signal.h" 32#include "l2cap_upper.h" 33 34#define BT_DEBUG_THIS_MODULE 35#define SUBMODULE_NAME "lower" 36#define SUBMODULE_COLOR 36 37#include <btDebug.h> 38 39status_t 40l2cap_receive(HciConnection* conn, net_buffer* buffer) 41{ 42 status_t error = B_OK; 43 uint16 dcid; 44 uint16 length; 45 46#ifdef DUMP_L2CAP_FRAME 47 flowf("DUMP:"); 48 for (uint i = 0; i < buffer->size; i++) { 49 uint8 c = 0; 50 gBufferModule->read(buffer, i, &c, 1); 51 dprintf("[%x]", c); 52 } 53 dprintf("\n"); 54#endif 55 // Check packet 56 if (buffer->size < sizeof(l2cap_hdr_t)) { 57 debugf("invalid L2CAP packet. Packet too small, len=%ld\n", buffer->size); 58 gBufferModule->free(buffer); 59 return EMSGSIZE; 60 61 } 62 63 // Get L2CAP header 64 NetBufferHeaderReader<l2cap_hdr_t> bufferHeader(buffer); 65 status_t status = bufferHeader.Status(); 66 if (status < B_OK) { 67 return ENOBUFS; 68 } 69 70 length = bufferHeader->length = le16toh(bufferHeader->length); 71 dcid = bufferHeader->dcid = le16toh(bufferHeader->dcid); 72 73 debugf("len=%d cid=%x\n", length, dcid); 74 75 bufferHeader.Remove(); // pulling 76 77 // Check payload size 78 if (length != buffer->size ) { 79 debugf("Payload length mismatch, packetlen=%d, bufferlen=%ld\n", 80 length, buffer->size); 81 gBufferModule->free(buffer); 82 return EMSGSIZE; 83 } 84 85 // Process packet 86 switch (dcid) { 87 case L2CAP_SIGNAL_CID: // L2CAP command 88 error = l2cap_process_signal_cmd(conn, buffer); 89 break; 90 91 case L2CAP_CLT_CID: // Connectionless packet 92 // error = l2cap_cl_receive(buffer); 93 flowf("CL FRAME!!\n"); 94 break; 95 96 default: // Data packet 97 error = l2cap_co_receive(conn, buffer, dcid); 98 break; 99 } 100 101 return (error); 102 103} 104 105 106struct bt_hci_module_info* btDevices = NULL; 107 108#if 0 109#pragma mark - thread conn sched - 110#endif 111 112static thread_id sConnectionThread; 113 114 115static void 116AddL2capHeader(L2capFrame* frame) 117{ 118 NetBufferPrepend<l2cap_hdr_t> bufferHeader(frame->buffer); 119 status_t status = bufferHeader.Status(); 120 121 if (status < B_OK) { 122 debugf("header could not be prepended! code=%d\n", frame->code); 123 return; 124 } 125 126 // fill 127 bufferHeader->length = htole16(frame->buffer->size - sizeof(l2cap_hdr_t)); 128 switch (frame->type) { 129 case L2CAP_C_FRAME: 130 bufferHeader->dcid = L2CAP_SIGNAL_CID; 131 break; 132 case L2CAP_G_FRAME: 133 bufferHeader->dcid = L2CAP_CLT_CID; 134 break; 135 default: 136 bufferHeader->dcid = frame->channel->dcid; 137 break; 138 } 139} 140 141 142void 143purge_connection(HciConnection* conn) 144{ 145 L2capFrame* frame; 146 bool containerCanBeDestroyed; 147 148 debugf("handle=%d\n", conn->handle); 149 150 mutex_lock(&conn->fLock); 151 152 frame = conn->OutGoingFrames.RemoveHead(); 153 154 mutex_unlock(&conn->fLock); 155 156// while ( frame != NULL) { 157 158 // Here is the place to decide how many l2cap signals we want to have 159 // per l2cap packet. 1 ATM 160 if (frame->type == L2CAP_C_FRAME && IS_SIGNAL_REQ(frame->code)) { 161 btCoreData->TimeoutSignal(frame, bluetooth_l2cap_rtx_timeout); 162 btCoreData->QueueSignal(frame); 163 containerCanBeDestroyed = false; 164 } else 165 containerCanBeDestroyed = true; 166 167 // Add the l2cap header 168 if (frame->buffer == NULL) 169 panic("Malformed frame in ongoing queue"); 170 171 AddL2capHeader(frame); 172 173 if (btDevices == NULL) 174 if (get_module(BT_HCI_MODULE_NAME, (module_info**)&btDevices) != B_OK) { 175 panic("l2cap: cannot get dev module"); 176 } // TODO: someone put it 177 178 179 debugf("type=%d, code=%d frame %p tolower\n", frame->type, frame->code, 180 frame->buffer); 181 182 frame->buffer->type = conn->handle; 183 btDevices->PostACL(conn->ndevice->index, frame->buffer); 184 185 // Only in the case that we need a response the frame container needs 186 // to be kept: Request C-Frames 187 if (containerCanBeDestroyed) { 188 delete frame; 189 } 190 191// frame = conn->OutGoingFrames.RemoveHead(); 192// } 193 194} 195 196 197static status_t 198connection_thread(void*) 199{ 200 int32 code; 201 ssize_t ssizePort; 202 ssize_t ssizeRead; 203 204 HciConnection* conn = NULL; 205 206 // TODO: Keep this a static var 207 port_id fPort = find_port(BLUETOOTH_CONNECTION_SCHED_PORT); 208 if (fPort == B_NAME_NOT_FOUND) 209 { 210 panic("BT Connection port has been deleted"); 211 } 212 213 while ((ssizePort = port_buffer_size(fPort)) != B_BAD_PORT_ID) { 214 215 if (ssizePort <= 0) { 216 debugf("Error %s\n", strerror(ssizePort)); 217 snooze(500 * 1000); 218 continue; 219 } 220 221 if (ssizePort > (ssize_t) sizeof(conn)) { 222 debugf("Message too big %ld\n", ssizePort); 223 snooze(500 * 1000); 224 continue; 225 } 226 227 ssizeRead = read_port(fPort, &code, &conn, ssizePort); 228 229 if (ssizeRead != ssizePort) { 230 debugf("Missmatch size port=%ld read=%ld\n", ssizePort, ssizeRead); 231 snooze(500 * 1000); 232 continue; 233 } 234 235 purge_connection(conn); 236 } 237 238 return B_OK; 239} 240 241 242status_t 243InitializeConnectionPurgeThread() 244{ 245 246 port_id fPort = find_port(BLUETOOTH_CONNECTION_SCHED_PORT); 247 if (fPort == B_NAME_NOT_FOUND) 248 { 249 fPort = create_port(16, BLUETOOTH_CONNECTION_SCHED_PORT); 250 debugf("Connection purge port created %ld\n",fPort); 251 } 252 253 // This thread has to catch up connections before first package is sent. 254 sConnectionThread = spawn_kernel_thread(connection_thread, 255 "bluetooth connection purge", B_URGENT_DISPLAY_PRIORITY, NULL); 256 257 if (sConnectionThread >= B_OK) 258 return resume_thread(sConnectionThread); 259 else 260 return B_ERROR; 261} 262 263 264status_t 265QuitConnectionPurgeThread() 266{ 267 status_t status; 268 269 port_id fPort = find_port(BLUETOOTH_CONNECTION_SCHED_PORT); 270 if (fPort != B_NAME_NOT_FOUND) 271 close_port(fPort); 272 273 flowf("Connection port deleted\n"); 274 wait_for_thread(sConnectionThread, &status); 275 return status; 276} 277 278 279void 280SchedConnectionPurgeThread(HciConnection* conn) 281{ 282 port_id port = find_port(BLUETOOTH_CONNECTION_SCHED_PORT); 283 284 HciConnection* temp = conn; 285 286 if (port == B_NAME_NOT_FOUND) 287 panic("BT Connection Port Deleted"); 288 289 status_t error = write_port(port, (uint32) conn, &temp, sizeof(conn)); 290 291 if (error != B_OK) 292 panic("BT Connection sched failed"); 293 294} 295