- 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:
@@ -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
|
||||||
@@ -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);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -36,15 +36,17 @@ 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();
|
||||||
@@ -52,12 +54,30 @@ DumpHciConnections(int argc, char** argv)
|
|||||||
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)
|
||||||
{
|
{
|
||||||
@@ -172,7 +192,8 @@ bluetooth_core_data_module_info sBCDModule = {
|
|||||||
unTimeoutSignal,
|
unTimeoutSignal,
|
||||||
SpawmFrame,
|
SpawmFrame,
|
||||||
SpawmSignal,
|
SpawmSignal,
|
||||||
AcknowledgeSignal
|
AcknowledgeSignal,
|
||||||
|
QueueSignal,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,21 @@
|
|||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
@@ -34,7 +49,7 @@ AddConnection(uint16 handle, int type, bdaddr_t* dst, hci_id hid)
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +107,9 @@ AcknowledgeSignal(L2capFrame* frame)
|
|||||||
|
|
||||||
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);
|
||||||
@@ -105,3 +120,20 @@ AcknowledgeSignal(L2capFrame* frame)
|
|||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
if (fAcceptSemaphore != -1) {
|
||||||
|
debugf("server socket not handling any channel %p\n", this);
|
||||||
|
|
||||||
|
delete_sem(fAcceptSemaphore);
|
||||||
|
// TODO: Clean needed stuff
|
||||||
|
// Unbind?
|
||||||
return B_OK;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -112,17 +136,17 @@ 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,19 +239,16 @@ 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*)((*_acceptedSocket)->first_protocol))->fState = ESTABLISHED;
|
||||||
((L2capEndpoint*)socket)->fChannel = fChannel;
|
|
||||||
|
|
||||||
// point parent
|
|
||||||
((L2capEndpoint*)socket)->fPeerEndpoint = this;
|
|
||||||
|
|
||||||
// unassign any channel for the parent endpoint
|
// unassign any channel for the parent endpoint
|
||||||
fChannel = NULL;
|
fChannel = NULL;
|
||||||
|
// we are listening again
|
||||||
fState = LISTEN;
|
fState = LISTEN;
|
||||||
|
}
|
||||||
|
|
||||||
} while (status != B_OK);
|
} while (status != B_OK);
|
||||||
|
|
||||||
@@ -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) {
|
||||||
|
debugf("Could not spawn child for Endpoint %p\n", this);
|
||||||
|
// TODO: Handle situation
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fChannel->configuration = &configuration;
|
L2capEndpoint* endpoint = (L2capEndpoint*)newSocket->first_protocol;
|
||||||
|
|
||||||
debugf("Endpoint %p for psm %d, schannel %x dchannel %x\n", this,
|
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);
|
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);
|
|
||||||
|
// TODO: Some more checkins / uninit
|
||||||
|
EndpointList.Remove(endpoint);
|
||||||
|
|
||||||
|
delete endpoint;
|
||||||
|
|
||||||
delete protocol;
|
|
||||||
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>
|
||||||
|
|
||||||
@@ -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();
|
frame = conn->OutGoingFrames.RemoveHead();
|
||||||
|
|
||||||
|
mutex_unlock(&conn->fLock);
|
||||||
|
|
||||||
// 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,8 +130,9 @@ 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
|
||||||
@@ -147,7 +153,7 @@ purge_connection(HciConnection* conn)
|
|||||||
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
|
||||||
|
|
||||||
@@ -174,7 +180,7 @@ connection_thread(void *)
|
|||||||
|
|
||||||
// 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");
|
||||||
}
|
}
|
||||||
@@ -213,7 +219,7 @@ 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);
|
||||||
@@ -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");
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ l2cap_process_signal_cmd(HciConnection* conn, net_buffer* buffer)
|
|||||||
|
|
||||||
// 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;
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user