diff --git a/headers/private/bluetooth/btCoreData.h b/headers/private/bluetooth/btCoreData.h index 55a2226f0c..8885807667 100644 --- a/headers/private/bluetooth/btCoreData.h +++ b/headers/private/bluetooth/btCoreData.h @@ -6,6 +6,7 @@ #define _BTCOREDATA_H #include +#include #include #include @@ -30,6 +31,9 @@ typedef enum _connection_status { #ifdef __cplusplus struct HciConnection : DoublyLinkedListLinkImpl { + HciConnection(); + virtual ~HciConnection(); + hci_id Hid; struct net_device* ndevice; net_buffer* currentRxPacket; @@ -44,6 +48,8 @@ struct HciConnection : DoublyLinkedListLinkImpl { DoublyLinkedList ChannelList; DoublyLinkedList ExpectedResponses; DoublyLinkedList OutGoingFrames; + mutex fLock; + mutex fLockExpected; }; #else @@ -84,7 +90,7 @@ struct L2capChannel : DoublyLinkedListLinkImpl { uint16 psm; uint8 ident; uint8 cfgState; - + channel_status state; ChannelConfiguration* configuration; L2capEndpoint* endpoint; @@ -154,9 +160,10 @@ struct bluetooth_core_data_module_info { struct L2capFrame* (*SignalByIdent)(struct HciConnection* conn, uint8 ident); status_t (*TimeoutSignal)(struct L2capFrame* frame, uint32 timeo); status_t (*UnTimeoutSignal)(struct L2capFrame* frame); - struct L2capFrame* (*SpawnFrame)(struct HciConnection* conn, net_buffer* buffer, frame_type frame); + struct L2capFrame* (*SpawnFrame)(struct HciConnection* conn, struct L2capChannel* channel, net_buffer* buffer, frame_type frame); struct L2capFrame* (*SpawnSignal)(struct HciConnection* conn, struct L2capChannel* channel, net_buffer* buffer, uint8 ident, uint8 code); status_t (*AcknowledgeSignal)(struct L2capFrame* frame); + status_t (*QueueSignal)(struct L2capFrame* frame); }; diff --git a/src/add-ons/kernel/bluetooth/btCoreData/BTCoreData.cpp b/src/add-ons/kernel/bluetooth/btCoreData/BTCoreData.cpp index 7ba9919c80..1c93fc4ac9 100644 --- a/src/add-ons/kernel/bluetooth/btCoreData/BTCoreData.cpp +++ b/src/add-ons/kernel/bluetooth/btCoreData/BTCoreData.cpp @@ -34,53 +34,73 @@ ExistConnectionByHandle(uint16 handle, hci_id hid) static int DumpHciConnections(int argc, char** argv) { - HciConnection* conn; - L2capChannel* chan; + HciConnection* conn; + L2capChannel* chan; + L2capFrame* frame; DoublyLinkedList::Iterator iterator = sConnectionList.GetIterator(); while (iterator.HasNext()) { conn = iterator.Next(); - kprintf("\tLocalDevice=%lx Destination=%s handle=%#x type=%d outqueue=%ld expected=%ld\n", + kprintf("LocalDevice=%lx Destination=%s handle=%#x type=%d outqueue=%ld expected=%ld\n", conn->Hid, bdaddrUtils::ToString(conn->destination), conn->handle, conn->type, conn->OutGoingFrames.Count() , conn->ExpectedResponses.Count()); // each channel + kprintf("\tChannels\n"); DoublyLinkedList::Iterator channelIterator = conn->ChannelList.GetIterator(); while (channelIterator.HasNext()) { - chan = channelIterator.Next(); - kprintf("\t\tscid=%x dcid=%x state=%x cfg=%x\n", chan->scid, + chan = channelIterator.Next(); + kprintf("\t\tscid=%x dcid=%x state=%x cfg=%x\n", chan->scid, chan->dcid, chan->state, chan->cfgState); } + // Each outgoing + kprintf("\n\tOutGoingFrames\n"); + DoublyLinkedList::Iterator frameIterator = conn->OutGoingFrames.GetIterator(); + while (frameIterator.HasNext()) { + frame = frameIterator.Next(); + kprintf("\t\tscid=%x code=%x ident=%x type=%x, buffer=%p\n", frame->channel->scid, + frame->code, frame->ident, frame->type, frame->buffer); + } + + // Each expected + kprintf("\n\tExpectedFrames\n"); + DoublyLinkedList::Iterator frameExpectedIterator = conn->ExpectedResponses.GetIterator(); + while (frameExpectedIterator.HasNext()) { + frame = frameExpectedIterator.Next(); + kprintf("\t\tscid=%x code=%x ident=%x type=%x, buffer=%p\n", frame->channel->scid, + frame->code, frame->ident, frame->type, frame->buffer); + } } return 0; } + status_t PostEvent(net_device* ndev, void* event, size_t size) { struct hci_event_header* outgoingEvent = (struct hci_event_header*) event; status_t err; - + // Take actions on certain type of events. switch (outgoingEvent->ecode) { case HCI_EVENT_CONN_COMPLETE: { struct hci_ev_conn_complete* data = (struct hci_ev_conn_complete*)(outgoingEvent+1); - //TODO: XXX parse handle field + //TODO: XXX parse handle field HciConnection* conn = AddConnection(data->handle, BT_ACL, &data->bdaddr, ndev->index); if (conn == NULL) panic("no mem for conn desc"); conn->ndevice = ndev; debugf("Registered connection handle=%#x\n",data->handle); - + } break; case HCI_EVENT_DISCONNECTION_COMPLETE: { - struct hci_ev_disconnection_complete_reply* data = + struct hci_ev_disconnection_complete_reply* data = (struct hci_ev_disconnection_complete_reply*)(outgoingEvent+1); RemoveConnection(data->handle, ndev->index); debugf("unRegistered connection handle=%#x\n",data->handle); @@ -90,13 +110,13 @@ PostEvent(net_device* ndev, void* event, size_t size) // forward to bluetooth server port_id port = find_port(BT_USERLAND_PORT_NAME); if (port != B_NAME_NOT_FOUND) { - + err = write_port_etc(port, PACK_PORTCODE(BT_EVENT, ndev->index, -1), event, size, B_TIMEOUT, 1*1000*1000); - - if (err != B_OK) + + if (err != B_OK) debugf("Error posting userland %s\n", strerror(err)); - + } else { flowf("ERROR:bluetooth_server not found for posting\n"); err = B_NAME_NOT_FOUND; @@ -115,23 +135,23 @@ bcd_std_ops(int32 op, ...) switch (op) { case B_MODULE_INIT: new (&sConnectionList) DoublyLinkedList; - add_debugger_command("btConnections", &DumpHciConnections, + add_debugger_command("btConnections", &DumpHciConnections, "Lists Bluetooth Connections with RemoteDevices & channels"); - + status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule); if (status < B_OK) { return status; } return B_OK; - + break; case B_MODULE_UNINIT: - + remove_debugger_command("btConnections", &DumpHciConnections); put_module(NET_BUFFER_MODULE_NAME); - + return B_OK; break; } @@ -172,7 +192,8 @@ bluetooth_core_data_module_info sBCDModule = { unTimeoutSignal, SpawmFrame, SpawmSignal, - AcknowledgeSignal + AcknowledgeSignal, + QueueSignal, }; diff --git a/src/add-ons/kernel/bluetooth/btCoreData/ConnectionInterface.cpp b/src/add-ons/kernel/bluetooth/btCoreData/ConnectionInterface.cpp index 6f1e8ae3b4..d998cc4ff8 100644 --- a/src/add-ons/kernel/bluetooth/btCoreData/ConnectionInterface.cpp +++ b/src/add-ons/kernel/bluetooth/btCoreData/ConnectionInterface.cpp @@ -21,20 +21,35 @@ void PurgeChannels(HciConnection* conn); + +HciConnection::HciConnection() +{ + mutex_init(&fLock, "conn outgoing"); + mutex_init(&fLockExpected, "frame expected"); +} + + +HciConnection::~HciConnection() +{ + mutex_destroy(&fLock); + mutex_destroy(&fLockExpected); +} + + HciConnection* AddConnection(uint16 handle, int type, bdaddr_t* dst, hci_id hid) { // Create connection descriptor - + HciConnection* conn = ConnectionByHandle(handle, hid); - if (conn != NULL) + if (conn != NULL) goto update; - + conn = new (std::nothrow) HciConnection; if (conn == NULL) goto bail; - - memset(conn, 0, sizeof(HciConnection)); + + //memset(conn, 0, sizeof(HciConnection)); conn->currentRxPacket = NULL; conn->currentRxExpectedLength = 0; diff --git a/src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.cpp b/src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.cpp index 84061ba1dd..7b9d5c16a0 100644 --- a/src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.cpp +++ b/src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.cpp @@ -5,22 +5,27 @@ #define SUBMODULE_COLOR 31 #include +#include L2capFrame* SignalByIdent(HciConnection* conn, uint8 ident) { L2capFrame* frame; + mutex_lock(&conn->fLockExpected); DoublyLinkedList::Iterator iterator = conn->ExpectedResponses.GetIterator(); while (iterator.HasNext()) { frame = iterator.Next(); if (frame->type == L2CAP_C_FRAME && frame->ident == ident) { + mutex_unlock(&frame->conn->fLockExpected); return frame; } } + mutex_unlock(&conn->fLockExpected); + return NULL; } @@ -45,7 +50,7 @@ unTimeoutSignal(L2capFrame* frame) L2capFrame* -SpawmFrame(HciConnection* conn, net_buffer* buffer, frame_type type) +SpawmFrame(HciConnection* conn, L2capChannel* channel, net_buffer* buffer, frame_type type) { if (buffer == NULL) panic("Null Buffer to outgoing queue"); @@ -53,13 +58,17 @@ SpawmFrame(HciConnection* conn, net_buffer* buffer, frame_type type) L2capFrame* frame = new (std::nothrow) L2capFrame; frame->conn = conn; - frame->channel = NULL; // TODO: needed? + frame->channel = channel; // TODO: maybe only scid needed frame->buffer = buffer; frame->type = type; + mutex_lock(&conn->fLock); + conn->OutGoingFrames.Add(frame, true); + mutex_unlock(&conn->fLock); + return frame; } @@ -73,15 +82,19 @@ SpawmSignal(HciConnection* conn, L2capChannel* channel, net_buffer* buffer, uint L2capFrame* frame = new (std::nothrow) L2capFrame; frame->conn = conn; - frame->channel = channel; // TODO: needed? + frame->channel = channel; // TODO: not specific descriptor should be required frame->buffer = buffer; frame->type = L2CAP_C_FRAME; frame->ident = ident; frame->code = code; + mutex_lock(&conn->fLock); + conn->OutGoingFrames.Add(frame, true); + mutex_unlock(&conn->fLock); + return frame; } @@ -91,17 +104,36 @@ AcknowledgeSignal(L2capFrame* frame) { if (frame != NULL) { - + if (frame->type == L2CAP_C_FRAME) { unTimeoutSignal(frame); - frame->conn->ExpectedResponses.Remove(frame); + mutex_lock(&frame->conn->fLockExpected); + // frame->conn->ExpectedResponses.Remove(frame); + mutex_unlock(&frame->conn->fLockExpected); } - + gBufferModule->free(frame->buffer); delete frame; - + return B_OK; } return B_ERROR; } + + +status_t +QueueSignal(L2capFrame* frame) +{ + if (frame != NULL) { + + if (frame->type == L2CAP_C_FRAME) { + mutex_lock(&frame->conn->fLockExpected); + frame->conn->ExpectedResponses.Add(frame); + mutex_unlock(&frame->conn->fLockExpected); + return B_OK; + } + } + + return B_ERROR; +} diff --git a/src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.h b/src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.h index 84c1c3ea25..18701c4230 100644 --- a/src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.h +++ b/src/add-ons/kernel/bluetooth/btCoreData/FrameInterface.h @@ -17,7 +17,7 @@ status_t unTimeoutSignal(L2capFrame* frame); L2capFrame* -SpawmFrame(HciConnection* conn, net_buffer* buffer, frame_type frame); +SpawmFrame(HciConnection* conn, L2capChannel* channel, net_buffer* buffer, frame_type frame); L2capFrame* SpawmSignal(HciConnection* conn, L2capChannel* channel, net_buffer* buffer, uint8 ident, uint8 code); @@ -25,4 +25,7 @@ SpawmSignal(HciConnection* conn, L2capChannel* channel, net_buffer* buffer, uint status_t AcknowledgeSignal(L2capFrame* frame); +status_t +QueueSignal(L2capFrame* frame); + #endif diff --git a/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.cpp b/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.cpp index 613a685dd9..275bf9f8c6 100644 --- a/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.cpp +++ b/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.cpp @@ -4,6 +4,7 @@ */ #include "L2capEndpoint.h" #include "l2cap_address.h" +#include "l2cap_upper.h" #include #include @@ -33,22 +34,23 @@ L2capEndpoint::L2capEndpoint(net_socket* socket) : ProtocolSocket(socket), fConfigurationSet(false), - fPeerEndpoint(NULL), fAcceptSemaphore(-1), + fPeerEndpoint(NULL), fChannel(NULL) { debugf("[%ld] %p\n", find_thread(NULL), this); /* Set MTU and flow control settings to defaults */ - configuration.imtu = L2CAP_MTU_DEFAULT; - memcpy(&configuration.iflow, &default_qos , sizeof(l2cap_flow_t) ); + fConfiguration.imtu = L2CAP_MTU_DEFAULT; + memcpy(&fConfiguration.iflow, &default_qos , sizeof(l2cap_flow_t) ); - configuration.omtu = L2CAP_MTU_DEFAULT; - memcpy(&configuration.oflow, &default_qos , sizeof(l2cap_flow_t) ); + fConfiguration.omtu = L2CAP_MTU_DEFAULT; + memcpy(&fConfiguration.oflow, &default_qos , sizeof(l2cap_flow_t) ); - configuration.flush_timo = L2CAP_FLUSH_TIMO_DEFAULT; - configuration.link_timo = L2CAP_LINK_TIMO_DEFAULT; + fConfiguration.flush_timo = L2CAP_FLUSH_TIMO_DEFAULT; + fConfiguration.link_timo = L2CAP_LINK_TIMO_DEFAULT; + // TODO: XXX not for listening endpoints, imtu should be known first gStackModule->init_fifo(&fReceivingFifo, "l2cap recvfifo", L2CAP_MTU_DEFAULT); } @@ -57,6 +59,7 @@ L2capEndpoint::~L2capEndpoint() { debugf("[%ld] %p\n", find_thread(NULL), this); + gStackModule->uninit_fifo(&fReceivingFifo); } @@ -95,7 +98,28 @@ L2capEndpoint::Close() { debugf("[%ld] %p\n", find_thread(NULL), this); - return B_OK; + if (fAcceptSemaphore != -1) { + debugf("server socket not handling any channel %p\n", this); + + delete_sem(fAcceptSemaphore); + // TODO: Clean needed stuff + // Unbind? + return B_OK; + + } else { + // Client endpoint + if (fState == CLOSING) { + debugf("Already closed by peer %p\n", this); + // TODO: Clean needed stuff + + return B_OK; + } else { + // Issue Disconnection request over the channel + fState = CLOSED; + return l2cap_upper_dis_req(fChannel); + } + } + } @@ -111,18 +135,18 @@ L2capEndpoint::Free() status_t L2capEndpoint::Bind(const struct sockaddr *_address) { - if (_address == NULL) - panic("null adrresss!"); + if (_address == NULL) + return B_ERROR; if (_address->sa_family != AF_BLUETOOTH ) return EAFNOSUPPORT; - // TODO: Check socladdr_l2cap size + //if (_address->sa_len != sizeof(struct sockaddr_l2cap)) + // return EAFNOSUPPORT; // TODO: Check if that PSM is already bound // return EADDRINUSE; - // TODO: Check if the PSM is valid, check assigned numbers document for valid // psm available to applications. // All PSM values shall be ODD, that is, the least significant bit of the least @@ -136,10 +160,9 @@ L2capEndpoint::Bind(const struct sockaddr *_address) memcpy(&socket->address, _address, sizeof(struct sockaddr_l2cap)); socket->address.ss_len = sizeof(struct sockaddr_l2cap); - fState = CLOSED; + fState = BOUND; return B_OK; - } @@ -157,8 +180,8 @@ L2capEndpoint::Listen(int backlog) { debugf("[%ld] %p\n", find_thread(NULL), this); - if (fState != CLOSED) { - flowf("Invalid State\n"); + if (fState != BOUND) { + debugf("Invalid State %p\n", this); return B_BAD_VALUE; } @@ -216,20 +239,17 @@ L2capEndpoint::Accept(net_socket **_acceptedSocket) // locker.Lock(); status = gSocketModule->dequeue_connected(socket, _acceptedSocket); - if (status != B_OK) + if (status != B_OK) { debugf("Could not dequeue socket %s\n", strerror(status)); - - //TODO: Establish relationship with the negotiated channel by the parent endpoint - ((L2capEndpoint*)socket)->fChannel = fChannel; - - // point parent - ((L2capEndpoint*)socket)->fPeerEndpoint = this; - - // unassign any channel for the parent endpoint - fChannel = NULL; - - fState = LISTEN; - + } else { + + ((L2capEndpoint*)((*_acceptedSocket)->first_protocol))->fState = ESTABLISHED; + // unassign any channel for the parent endpoint + fChannel = NULL; + // we are listening again + fState = LISTEN; + } + } while (status != B_OK); return status; @@ -255,6 +275,10 @@ L2capEndpoint::Receive(const iovec *vecs, size_t vecCount, debugf("[%ld] %p Receive(%p, %ld)\n", find_thread(NULL), this, vecs, vecCount); + if (fState != ESTABLISHED) { + debugf("Invalid State %p\n", this); + return B_BAD_VALUE; + } return B_OK; } @@ -263,6 +287,12 @@ L2capEndpoint::Receive(const iovec *vecs, size_t vecCount, ssize_t L2capEndpoint::ReadData(size_t numBytes, uint32 flags, net_buffer** _buffer) { + debugf("e->%p num=%ld, f=%ld)\n", this, numBytes, flags); + + if (fState != ESTABLISHED) { + debugf("Invalid State %p\n", this); + return B_BAD_VALUE; + } return gStackModule->fifo_dequeue_buffer(&fReceivingFifo, flags, B_INFINITE_TIMEOUT, _buffer); @@ -274,7 +304,7 @@ L2capEndpoint::Sendable() { debugf("[%ld] %p\n", find_thread(NULL), this); - return 0; + return B_OK; } @@ -311,14 +341,31 @@ L2capEndpoint::ForPsm(uint16 psm) void L2capEndpoint::BindToChannel(L2capChannel* channel) { - fChannel = channel; - fChannel->endpoint = this; - - fChannel->configuration = &configuration; - - debugf("Endpoint %p for psm %d, schannel %x dchannel %x\n", this, - channel->psm, channel->scid, channel->dcid); + net_socket* newSocket; + status_t error = gSocketModule->spawn_pending_socket(socket, &newSocket); + if (error != B_OK) { + debugf("Could not spawn child for Endpoint %p\n", this); + // TODO: Handle situation + return; + } + L2capEndpoint* endpoint = (L2capEndpoint*)newSocket->first_protocol; + + endpoint->fChannel = channel; + endpoint->fPeerEndpoint = this; + + channel->endpoint = endpoint; + + debugf("new socket %p/e->%p from parent %p/e->%p\n", newSocket, endpoint, socket, this); + + // Provide the channel the configuration set by the user socket + channel->configuration = &fConfiguration; + + // It might be used keep the last negotiated channel + // fChannel = channel; + + debugf("New endpoint %p for psm %d, schannel %x dchannel %x\n", endpoint, + channel->psm, channel->scid, channel->dcid); } @@ -328,12 +375,23 @@ L2capEndpoint::MarkEstablished() debugf("Endpoint %p for psm %d, schannel %x dchannel %x\n", this, fChannel->psm, fChannel->scid, fChannel->dcid); - net_socket* newSocket; - status_t error = gSocketModule->spawn_pending_socket(socket, &newSocket); - - gSocketModule->set_connected(newSocket); - - release_sem(fAcceptSemaphore); + status_t error = gSocketModule->set_connected(socket); + if (error == B_OK) { + release_sem(fPeerEndpoint->fAcceptSemaphore); + } else { + debugf("Could not set child Endpoint %p %s\n", this, strerror(error)); + } return error; } + + +status_t +L2capEndpoint::MarkClosed() +{ + flowf("\n"); + fState = CLOSED; + + return B_OK; +} + diff --git a/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.h b/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.h index cc71d3938f..4abf635121 100644 --- a/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.h +++ b/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.h @@ -67,6 +67,7 @@ public: void BindToChannel(L2capChannel* channel); status_t MarkEstablished(); + status_t MarkClosed(); static L2capEndpoint* ForPsm(uint16 psm); @@ -75,17 +76,16 @@ public: return fConfigurationSet; } - ChannelConfiguration configuration; - net_fifo fReceivingFifo; + ChannelConfiguration fConfiguration; bool fConfigurationSet; + net_fifo fReceivingFifo; private: typedef enum { // establishing a connection CLOSED, + BOUND, LISTEN, - SYNCHRONIZE_SENT, - SYNCHRONIZE_RECEIVED, ESTABLISHED, // peer closes the connection @@ -101,9 +101,10 @@ private: mutex fLock; State fState; - L2capEndpoint* fPeerEndpoint; sem_id fAcceptSemaphore; + L2capEndpoint* fPeerEndpoint; L2capChannel* fChannel; + }; diff --git a/src/add-ons/kernel/network/protocols/l2cap/l2cap.cpp b/src/add-ons/kernel/network/protocols/l2cap/l2cap.cpp index d5668a9273..632cede0f0 100644 --- a/src/add-ons/kernel/network/protocols/l2cap/l2cap.cpp +++ b/src/add-ons/kernel/network/protocols/l2cap/l2cap.cpp @@ -64,7 +64,7 @@ l2cap_init_protocol(net_socket* socket) { flowf("\n"); - L2capEndpoint* protocol = new (std::nothrow) L2capEndpoint(socket); + L2capEndpoint* protocol = new(std::nothrow) L2capEndpoint(socket); if (protocol == NULL) return NULL; @@ -79,10 +79,13 @@ l2cap_uninit_protocol(net_protocol* protocol) { flowf("\n"); - // TODO: Some more checkins / uninit - EndpointList.Remove((L2capEndpoint*)protocol); + L2capEndpoint* endpoint = static_cast(protocol); - delete protocol; + // TODO: Some more checkins / uninit + EndpointList.Remove(endpoint); + + delete endpoint; + return B_OK; } diff --git a/src/add-ons/kernel/network/protocols/l2cap/l2cap_lower.cpp b/src/add-ons/kernel/network/protocols/l2cap/l2cap_lower.cpp index 87dee50209..42601eb536 100644 --- a/src/add-ons/kernel/network/protocols/l2cap/l2cap_lower.cpp +++ b/src/add-ons/kernel/network/protocols/l2cap/l2cap_lower.cpp @@ -18,6 +18,7 @@ */ #include #include +#include #include @@ -41,7 +42,7 @@ l2cap_receive(HciConnection* conn, net_buffer* buffer) status_t error = B_OK; uint16 dcid; uint16 length; - + /* Check packet */ if (buffer->size < sizeof(l2cap_hdr_t)) { debugf("invalid L2CAP packet. Packet too small, len=%ld\n", buffer->size); @@ -103,19 +104,23 @@ static thread_id sConnectionThread; void purge_connection(HciConnection* conn) { - L2capFrame* frame; - debugf("handle=%d\n",conn->handle); + debugf("handle=%d\n", conn->handle); + + mutex_lock(&conn->fLock); + + frame = conn->OutGoingFrames.RemoveHead(); + + mutex_unlock(&conn->fLock); - frame = conn->OutGoingFrames.RemoveHead(); // while ( frame != NULL) { // Here is the place to decide how many l2cap signals we want to have - // per l2cap packet. 1 ATM + // per l2cap packet. 1 ATM if (frame->type == L2CAP_C_FRAME) { btCoreData->TimeoutSignal(frame, bluetooth_l2cap_rtx_timeout); - conn->ExpectedResponses.Add(frame); + btCoreData->QueueSignal(frame); } // Add the l2cap header @@ -125,10 +130,11 @@ purge_connection(HciConnection* conn) NetBufferPrepend bufferHeader(frame->buffer); status_t status = bufferHeader.Status(); if (status < B_OK) { - // free the buffer -//! continue; + debugf("l2cap header could not be prepended!! frame code=%d\n", frame->code); + return; + } - + // fill bufferHeader->length = htole16(frame->buffer->size - sizeof(l2cap_hdr_t)); switch (frame->type) { @@ -141,17 +147,17 @@ purge_connection(HciConnection* conn) default: bufferHeader->dcid = frame->channel->dcid; break; - - } - + + } + bufferHeader.Sync(); - - if (btDevices == NULL) - if (get_module(NET_BLUETOOTH_DEVICE_NAME,(module_info**)&btDevices) != B_OK) { + + if (btDevices == NULL) + if (get_module(NET_BLUETOOTH_DEVICE_NAME, (module_info**)&btDevices) != B_OK) { panic("l2cap: cannot get dev module"); } // TODO: someone put it - + debugf("dev %p frame %p tolower\n", conn->ndevice, frame->buffer); frame->buffer->type = conn->handle; @@ -159,7 +165,7 @@ purge_connection(HciConnection* conn) // frame = conn->OutGoingFrames.RemoveHead(); // } - + } @@ -171,36 +177,36 @@ connection_thread(void *) ssize_t ssizeRead; HciConnection* conn = NULL; - + // TODO: Keep this a static var port_id fPort = find_port(BLUETOOTH_CONNECTION_SCHED_PORT); - if ( fPort == B_NAME_NOT_FOUND ) + if (fPort == B_NAME_NOT_FOUND) { panic("BT Connection port has been deleted"); } - while ((ssizePort = port_buffer_size(fPort)) != B_BAD_PORT_ID) { + while ((ssizePort = port_buffer_size(fPort)) != B_BAD_PORT_ID) { if (ssizePort <= 0) { debugf("Error %s\n", strerror(ssizePort)); snooze(500*1000); continue; } - + if (ssizePort > (ssize_t) sizeof(conn)) { debugf("Message too big %ld\n", ssizePort); snooze(500*1000); continue; } - ssizeRead = read_port(fPort, &code, &conn, ssizePort); + ssizeRead = read_port(fPort, &code, &conn, ssizePort); if (ssizeRead != ssizePort) { debugf("Missmatch size port=%ld read=%ld\n", ssizePort, ssizeRead); snooze(500*1000); continue; } - + purge_connection(conn); } @@ -213,12 +219,12 @@ InitializeConnectionPurgeThread() { port_id fPort = find_port(BLUETOOTH_CONNECTION_SCHED_PORT); - if ( fPort == B_NAME_NOT_FOUND ) + if (fPort == B_NAME_NOT_FOUND) { fPort = create_port(16, BLUETOOTH_CONNECTION_SCHED_PORT); debugf("Connection purge port created %ld\n",fPort); } - + // This thread has to catch up connections before first package is sent. sConnectionThread = spawn_kernel_thread(connection_thread, "bluetooth connection purge", B_URGENT_DISPLAY_PRIORITY, NULL); @@ -236,7 +242,7 @@ QuitConnectionPurgeThread() status_t status; port_id fPort = find_port(BLUETOOTH_CONNECTION_SCHED_PORT); - if ( fPort != B_NAME_NOT_FOUND ) + if (fPort != B_NAME_NOT_FOUND) close_port(fPort); flowf("Connection port deleted\n"); @@ -246,17 +252,17 @@ QuitConnectionPurgeThread() void -SchedConnectionPurgeThread(HciConnection* conn) +SchedConnectionPurgeThread(HciConnection* conn) { port_id port = find_port(BLUETOOTH_CONNECTION_SCHED_PORT); HciConnection* temp = conn; - if (port == B_NAME_NOT_FOUND) + if (port == B_NAME_NOT_FOUND) panic("BT Connection Port Deleted"); status_t error = write_port(port, (uint32) conn, &temp, sizeof(conn)); - + //debugf("error post %s port=%ld size=%ld\n", strerror(error), port, sizeof(conn)); if (error != B_OK) diff --git a/src/add-ons/kernel/network/protocols/l2cap/l2cap_signal.cpp b/src/add-ons/kernel/network/protocols/l2cap/l2cap_signal.cpp index 2fc0440e27..df0e5bac20 100644 --- a/src/add-ons/kernel/network/protocols/l2cap/l2cap_signal.cpp +++ b/src/add-ons/kernel/network/protocols/l2cap/l2cap_signal.cpp @@ -137,59 +137,59 @@ l2cap_process_signal_cmd(HciConnection* conn, net_buffer* buffer) /* Process command processors responsible to delete the command*/ switch (processingCode) { - case L2CAP_CMD_REJ: - l2cap_process_cmd_rej(conn, processingIdent, buffer); - break; + case L2CAP_CMD_REJ: + l2cap_process_cmd_rej(conn, processingIdent, buffer); + break; - case L2CAP_CON_REQ: - l2cap_process_con_req(conn, processingIdent, buffer); - break; + case L2CAP_CON_REQ: + l2cap_process_con_req(conn, processingIdent, buffer); + break; - case L2CAP_CON_RSP: - l2cap_process_con_rsp(conn, processingIdent, buffer); - break; + case L2CAP_CON_RSP: + l2cap_process_con_rsp(conn, processingIdent, buffer); + break; - case L2CAP_CFG_REQ: - l2cap_process_cfg_req(conn, processingIdent, buffer); - break; + case L2CAP_CFG_REQ: + l2cap_process_cfg_req(conn, processingIdent, buffer); + break; - case L2CAP_CFG_RSP: - l2cap_process_cfg_rsp(conn, processingIdent, buffer); - break; + case L2CAP_CFG_RSP: + l2cap_process_cfg_rsp(conn, processingIdent, buffer); + break; - case L2CAP_DISCON_REQ: - l2cap_process_discon_req(conn, processingIdent, buffer); - break; + case L2CAP_DISCON_REQ: + l2cap_process_discon_req(conn, processingIdent, buffer); + break; - case L2CAP_DISCON_RSP: - l2cap_process_discon_rsp(conn, processingIdent, buffer); - break; + case L2CAP_DISCON_RSP: + l2cap_process_discon_rsp(conn, processingIdent, buffer); + break; - case L2CAP_ECHO_REQ: - l2cap_process_echo_req(conn, processingIdent, buffer); - break; + case L2CAP_ECHO_REQ: + l2cap_process_echo_req(conn, processingIdent, buffer); + break; - case L2CAP_ECHO_RSP: - l2cap_process_echo_rsp(conn, processingIdent, buffer); - break; + case L2CAP_ECHO_RSP: + l2cap_process_echo_rsp(conn, processingIdent, buffer); + break; - case L2CAP_INFO_REQ: - l2cap_process_info_req(conn, processingIdent, buffer); - break; + case L2CAP_INFO_REQ: + l2cap_process_info_req(conn, processingIdent, buffer); + break; - case L2CAP_INFO_RSP: - l2cap_process_info_rsp(conn, processingIdent, buffer); - break; + case L2CAP_INFO_RSP: + l2cap_process_info_rsp(conn, processingIdent, buffer); + break; - default: - debugf("unknown L2CAP signaling command, code=%#x, ident=%d\n", + default: + debugf("unknown L2CAP signaling command, code=%#x, ident=%d\n", processingCode, processingIdent); - // Send L2CAP_CommandRej. Do not really care about the result - // ORD: Remiaining commands in the same packet are also to be rejected -/* send_l2cap_reject(con, processingIdent, L2CAP_REJ_NOT_UNDERSTOOD, 0, 0, 0);*/ - gBufferModule->free(m); - break; + // Send L2CAP_CommandRej. Do not really care about the result + // ORD: Remiaining commands in the same packet are also to be rejected + /*send_l2cap_reject(con, processingIdent, L2CAP_REJ_NOT_UNDERSTOOD, 0, 0, 0);*/ + gBufferModule->free(m); + break; } // Is there still remaining size? processors should have pulled its content... @@ -213,7 +213,7 @@ l2cap_process_signal_cmd(HciConnection* conn, net_buffer* buffer) static status_t l2cap_process_con_req(HciConnection* conn, uint8 ident, net_buffer* buffer) { - L2capChannel* ch; + L2capChannel* channel; uint16 dcid, psm; /* Get con req data */ @@ -231,29 +231,29 @@ l2cap_process_con_req(HciConnection* conn, uint8 ident, net_buffer* buffer) /* Create new channel and send L2CA_ConnectInd notification to the upper layer protocol. */ - ch = btCoreData->AddChannel(conn, psm /*, dcid, ident*/); - if (ch == NULL) { + channel = btCoreData->AddChannel(conn, psm /*, dcid, ident*/); + if (channel == NULL) { flowf("No resources to create channel\n"); return (send_l2cap_con_rej(conn, ident, 0, dcid, L2CAP_NO_RESOURCES)); } else { - debugf("New channel created scid=%d\n", ch->scid); + debugf("New channel created scid=%d\n", channel->scid); } - ch->dcid = dcid; - ch->ident = ident; + channel->dcid = dcid; + channel->ident = ident; - status_t indicationStatus = l2cap_l2ca_con_ind(ch); + status_t indicationStatus = l2cap_l2ca_con_ind(channel); if ( indicationStatus == B_OK ) { - //ch->state = L2CAP_CHAN_W4_L2CA_CON_RSP; + //channel->state = L2CAP_CHAN_W4_L2CA_CON_RSP; } else if (indicationStatus == B_NO_MEMORY) { - /* send_l2cap_con_rej(con, ident, ch->scid, dcid, L2CAP_NO_RESOURCES);*/ - btCoreData->RemoveChannel(conn, ch->scid); + /* send_l2cap_con_rej(con, ident, channel->scid, dcid, L2CAP_NO_RESOURCES);*/ + btCoreData->RemoveChannel(conn, channel->scid); } else { - send_l2cap_con_rej(conn, ident, ch->scid, dcid, L2CAP_PSM_NOT_SUPPORTED); - btCoreData->RemoveChannel(conn, ch->scid); + send_l2cap_con_rej(conn, ident, channel->scid, dcid, L2CAP_PSM_NOT_SUPPORTED); + btCoreData->RemoveChannel(conn, channel->scid); } return (indicationStatus); @@ -688,7 +688,7 @@ reject: static status_t l2cap_process_discon_req(HciConnection* conn, uint8 ident, net_buffer* buffer) { - L2capChannel* ch = NULL; + L2capChannel* channel = NULL; L2capFrame* cmd = NULL; net_buffer* buff = NULL; uint16 scid; @@ -706,26 +706,26 @@ l2cap_process_discon_req(HciConnection* conn, uint8 ident, net_buffer* buffer) command.Remove(); /* Check if we have this channel and it is in valid state */ - ch = btCoreData->ChannelBySourceID(conn, dcid); - if (ch == NULL) { + channel = btCoreData->ChannelBySourceID(conn, dcid); + if (channel == NULL) { debugf("unexpected L2CAP_DisconnectReq message.Channel does not exist, " "cid=%d\n", dcid); goto reject; } /* XXX Verify channel state and reject if invalid -- is that true? */ - if (ch->state != L2CAP_CHAN_OPEN && ch->state != L2CAP_CHAN_CONFIG && - ch->state != L2CAP_CHAN_W4_L2CAP_DISCON_RSP) { + if (channel->state != L2CAP_CHAN_OPEN && channel->state != L2CAP_CHAN_CONFIG && + channel->state != L2CAP_CHAN_W4_L2CAP_DISCON_RSP) { debugf("unexpected L2CAP_DisconnectReq. Invalid channel state, cid=%d, " - "state=%d\n", dcid, ch->state); + "state=%d\n", dcid, channel->state); goto reject; } /* Match destination channel ID */ - if (ch->dcid != scid || ch->scid != dcid) { + if (channel->dcid != scid || channel->scid != dcid) { debugf("unexpected L2CAP_DisconnectReq. Channel IDs does not match, " "channel: scid=%d, dcid=%d, request: scid=%d, dcid=%d\n", - ch->scid, ch->dcid, scid, dcid); + channel->scid, channel->dcid, scid, dcid); goto reject; } @@ -736,22 +736,22 @@ l2cap_process_discon_req(HciConnection* conn, uint8 ident, net_buffer* buffer) */ flowf("Responding\n"); + + // inform upper if we were not actually already waiting + if (channel->state != L2CAP_CHAN_W4_L2CAP_DISCON_RSP) { + l2cap_l2ca_discon_ind(channel); // do not care about result + } + /* Send L2CAP_DisconnectRsp */ buff = l2cap_discon_rsp(ident, dcid, scid); - cmd = btCoreData->SpawnSignal(conn, ch, buff, ident, L2CAP_DISCON_RSP); + cmd = btCoreData->SpawnSignal(conn, channel, buff, ident, L2CAP_DISCON_RSP); if (cmd == NULL) return ENOMEM; /* Link command to the queue */ SchedConnectionPurgeThread(conn); - - ch->state = L2CAP_CHAN_W4_L2CA_DISCON_RSP; - - if (ch->state != L2CAP_CHAN_W4_L2CAP_DISCON_RSP) { - //INDICATION ng_l2cap_l2ca_discon_ind(ch); /* do not care about result */ - btCoreData->RemoveChannel(conn, ch->scid); - } + btCoreData->RemoveChannel(conn, channel->scid); return B_OK; diff --git a/src/add-ons/kernel/network/protocols/l2cap/l2cap_upper.cpp b/src/add-ons/kernel/network/protocols/l2cap/l2cap_upper.cpp index 2d5d772ddf..caeb57c7a8 100644 --- a/src/add-ons/kernel/network/protocols/l2cap/l2cap_upper.cpp +++ b/src/add-ons/kernel/network/protocols/l2cap/l2cap_upper.cpp @@ -94,6 +94,7 @@ l2cap_l2ca_cfg_rsp_ind(L2capChannel* channel) } else { // nothing special requested + channel->ident = btCoreData->ChannelAllocateIdent(channel->conn); net_buffer* buf = l2cap_cfg_req(channel->ident, channel->dcid, 0, NULL); L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf, channel->ident, L2CAP_CFG_REQ); @@ -116,6 +117,13 @@ l2cap_l2ca_cfg_rsp_ind(L2capChannel* channel) } +status_t +l2cap_l2ca_discon_ind(L2capChannel* channel) +{ + return channel->endpoint->MarkClosed(); +} + + status_t l2cap_upper_cfg_rsp(L2capChannel* channel) { @@ -137,6 +145,33 @@ l2cap_upper_con_rsp(HciConnection* conn, L2capChannel* channel) return B_OK; } +status_t +l2cap_upper_dis_req(L2capChannel* channel) +{ + + channel->ident = btCoreData->ChannelAllocateIdent(channel->conn); + + net_buffer* buf = l2cap_discon_req(channel->ident, channel->scid, channel->dcid); + L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf, + channel->ident, L2CAP_DISCON_REQ); + if (cmd == NULL) { + gBufferModule->free(buf); + return ENOMEM; + } + + channel->state = L2CAP_CHAN_W4_L2CA_DISCON_RSP; + + /* Link command to the queue */ + SchedConnectionPurgeThread(channel->conn); + return B_OK; + +} + + +#if 0 +#pragma mark - +#endif + status_t l2cap_co_receive(HciConnection* conn, net_buffer* buffer, uint16 dcid) diff --git a/src/add-ons/kernel/network/protocols/l2cap/l2cap_upper.h b/src/add-ons/kernel/network/protocols/l2cap/l2cap_upper.h index c921241cc0..c17e1988a4 100644 --- a/src/add-ons/kernel/network/protocols/l2cap/l2cap_upper.h +++ b/src/add-ons/kernel/network/protocols/l2cap/l2cap_upper.h @@ -9,9 +9,12 @@ status_t l2cap_l2ca_con_ind(L2capChannel* channel); status_t l2cap_l2ca_cfg_rsp_ind(L2capChannel* channel); +status_t l2cap_l2ca_discon_ind(L2capChannel* channel); + status_t l2cap_upper_con_rsp(HciConnection* conn, L2capChannel* channel); status_t l2cap_upper_cfg_rsp(L2capChannel* channel); +status_t l2cap_upper_dis_req(L2capChannel* channel); status_t l2cap_co_receive(HciConnection* conn, net_buffer* buffer, uint16 dcid);