- Proper implementation of accept/bind l2cap socket interface

- Add more debug info for the KDL debug command
- Request channel pointer also for non l2cap signal frames
- Add locks for packet queues



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