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#include <btDebug.h> 35 36 37status_t 38l2cap_receive(HciConnection* conn, net_buffer* buffer) 39{ 40 status_t error = B_OK; 41 uint16 dcid; 42 uint16 length; 43 44#ifdef DUMP_L2CAP_FRAME 45 dprintf("DUMP:"); 46 for (uint i = 0; i < buffer->size; i++) { 47 uint8 c = 0; 48 gBufferModule->read(buffer, i, &c, 1); 49 dprintf("[%x]", c); 50 } 51 dprintf("\n"); 52#endif 53 // Check packet 54 if (buffer->size < sizeof(l2cap_hdr_t)) { 55 ERROR("%s: invalid L2CAP packet. Packet too small, len=%" B_PRIu32 "\n", 56 __func__, buffer->size); 57 gBufferModule->free(buffer); 58 return EMSGSIZE; 59 60 } 61 62 // Get L2CAP header 63 NetBufferHeaderReader<l2cap_hdr_t> bufferHeader(buffer); 64 status_t status = bufferHeader.Status(); 65 if (status < B_OK) { 66 return ENOBUFS; 67 } 68 69 length = bufferHeader->length = le16toh(bufferHeader->length); 70 dcid = bufferHeader->dcid = le16toh(bufferHeader->dcid); 71 72 TRACE("%s: len=%d cid=%x\n", __func__, length, dcid); 73 74 bufferHeader.Remove(); // pulling 75 76 // Check payload size 77 if (length != buffer->size ) { 78 ERROR("%s: Payload length mismatch, packetlen=%d, bufferlen=%" B_PRIu32 79 "\n", __func__, length, buffer->size); 80 gBufferModule->free(buffer); 81 return EMSGSIZE; 82 } 83 84 // Process packet 85 switch (dcid) { 86 case L2CAP_SIGNAL_CID: // L2CAP command 87 error = l2cap_process_signal_cmd(conn, buffer); 88 break; 89 90 case L2CAP_CLT_CID: // Connectionless packet 91 // error = l2cap_cl_receive(buffer); 92 TRACE("%s: CL FRAME!!\n", __func__); 93 break; 94 95 default: // Data packet 96 error = l2cap_co_receive(conn, buffer, dcid); 97 break; 98 } 99 100 return (error); 101 102} 103 104 105struct bt_hci_module_info* btDevices = NULL; 106 107#if 0 108#pragma mark - thread conn sched - 109#endif 110 111static thread_id sConnectionThread; 112 113 114static void 115AddL2capHeader(L2capFrame* frame) 116{ 117 NetBufferPrepend<l2cap_hdr_t> bufferHeader(frame->buffer); 118 status_t status = bufferHeader.Status(); 119 120 if (status < B_OK) { 121 ERROR("%s: header could not be prepended! code=%d\n", __func__, 122 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 CALLED(); 146 L2capFrame* frame; 147 bool containerCanBeDestroyed; 148 149 mutex_lock(&conn->fLock); 150 151 frame = conn->OutGoingFrames.RemoveHead(); 152 153 mutex_unlock(&conn->fLock); 154 155// while ( frame != NULL) { 156 157 // Here is the place to decide how many l2cap signals we want to have 158 // per l2cap packet. 1 ATM 159 if (frame->type == L2CAP_C_FRAME && IS_SIGNAL_REQ(frame->code)) { 160 btCoreData->TimeoutSignal(frame, bluetooth_l2cap_rtx_timeout); 161 btCoreData->QueueSignal(frame); 162 containerCanBeDestroyed = false; 163 } else 164 containerCanBeDestroyed = true; 165 166 // Add the l2cap header 167 if (frame->buffer == NULL) 168 panic("Malformed frame in ongoing queue"); 169 170 AddL2capHeader(frame); 171 172 if (btDevices == NULL) 173 if (get_module(BT_HCI_MODULE_NAME, (module_info**)&btDevices) != B_OK) { 174 panic("l2cap: cannot get dev module"); 175 } // TODO: someone put it 176 177 178 TRACE("%s: type=%d, code=%d frame %p tolower\n", __func__, frame->type, 179 frame->code, frame->buffer); 180 181 frame->buffer->type = conn->handle; 182 btDevices->PostACL(conn->ndevice->index, frame->buffer); 183 184 // Only in the case that we need a response the frame container needs 185 // to be kept: Request C-Frames 186 if (containerCanBeDestroyed) { 187 delete frame; 188 } 189 190// frame = conn->OutGoingFrames.RemoveHead(); 191// } 192 193} 194 195 196static status_t 197connection_thread(void*) 198{ 199 int32 code; 200 ssize_t ssizePort; 201 ssize_t ssizeRead; 202 203 HciConnection* conn = NULL; 204 205 // TODO: Keep this a static var 206 port_id fPort = find_port(BLUETOOTH_CONNECTION_SCHED_PORT); 207 if (fPort == B_NAME_NOT_FOUND) { 208 panic("BT Connection port has been deleted"); 209 } 210 211 while ((ssizePort = port_buffer_size(fPort)) != B_BAD_PORT_ID) { 212 213 if (ssizePort <= 0) { 214 ERROR("%s: Error %s\n", __func__, strerror(ssizePort)); 215 snooze(500 * 1000); 216 continue; 217 } 218 219 if (ssizePort > (ssize_t) sizeof(conn)) { 220 ERROR("%s: Message too big %ld\n", __func__, ssizePort); 221 snooze(500 * 1000); 222 continue; 223 } 224 225 ssizeRead = read_port(fPort, &code, &conn, ssizePort); 226 227 if (ssizeRead != ssizePort) { 228 ERROR("%s: Mismatch size port=%ld read=%ld\n", __func__, 229 ssizePort, ssizeRead); 230 snooze(500 * 1000); 231 continue; 232 } 233 234 purge_connection(conn); 235 } 236 237 return B_OK; 238} 239 240 241status_t 242InitializeConnectionPurgeThread() 243{ 244 port_id fPort = find_port(BLUETOOTH_CONNECTION_SCHED_PORT); 245 if (fPort == B_NAME_NOT_FOUND) { 246 TRACE("%s: Creating connection purge port\n", __func__); 247 fPort = create_port(16, BLUETOOTH_CONNECTION_SCHED_PORT); 248 } 249 250 // This thread has to catch up connections before first package is sent. 251 sConnectionThread = spawn_kernel_thread(connection_thread, 252 "bluetooth connection purge", B_URGENT_DISPLAY_PRIORITY, NULL); 253 254 if (sConnectionThread >= B_OK) 255 return resume_thread(sConnectionThread); 256 else 257 return B_ERROR; 258} 259 260 261status_t 262QuitConnectionPurgeThread() 263{ 264 CALLED(); 265 status_t status; 266 267 port_id fPort = find_port(BLUETOOTH_CONNECTION_SCHED_PORT); 268 if (fPort != B_NAME_NOT_FOUND) 269 close_port(fPort); 270 271 wait_for_thread(sConnectionThread, &status); 272 return status; 273} 274 275 276void 277SchedConnectionPurgeThread(HciConnection* conn) 278{ 279 port_id port = find_port(BLUETOOTH_CONNECTION_SCHED_PORT); 280 281 HciConnection* temp = conn; 282 283 if (port == B_NAME_NOT_FOUND) 284 panic("BT Connection Port Deleted"); 285 286 status_t error = write_port(port, (addr_t)conn, &temp, sizeof(conn)); 287 288 if (error != B_OK) 289 panic("BT Connection sched failed"); 290 291} 292