- 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:
parent
cf3d8a746f
commit
31f8763031
@ -6,6 +6,7 @@
|
||||
#define _BTCOREDATA_H
|
||||
|
||||
#include <module.h>
|
||||
#include <lock.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
#include <util/DoublyLinkedQueue.h>
|
||||
|
||||
@ -30,6 +31,9 @@ typedef enum _connection_status {
|
||||
#ifdef __cplusplus
|
||||
|
||||
struct HciConnection : DoublyLinkedListLinkImpl<HciConnection> {
|
||||
HciConnection();
|
||||
virtual ~HciConnection();
|
||||
|
||||
hci_id Hid;
|
||||
struct net_device* ndevice;
|
||||
net_buffer* currentRxPacket;
|
||||
@ -44,6 +48,8 @@ struct HciConnection : DoublyLinkedListLinkImpl<HciConnection> {
|
||||
DoublyLinkedList<L2capChannel> ChannelList;
|
||||
DoublyLinkedList<L2capFrame> ExpectedResponses;
|
||||
DoublyLinkedList<L2capFrame> OutGoingFrames;
|
||||
mutex fLock;
|
||||
mutex fLockExpected;
|
||||
};
|
||||
|
||||
#else
|
||||
@ -84,7 +90,7 @@ struct L2capChannel : DoublyLinkedListLinkImpl<L2capChannel> {
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
|
@ -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<HciConnection>::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<L2capChannel>::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<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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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<HciConnection>;
|
||||
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,
|
||||
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -5,22 +5,27 @@
|
||||
#define SUBMODULE_COLOR 31
|
||||
#include <btDebug.h>
|
||||
|
||||
#include <lock.h>
|
||||
|
||||
L2capFrame*
|
||||
SignalByIdent(HciConnection* conn, uint8 ident)
|
||||
{
|
||||
L2capFrame* frame;
|
||||
|
||||
mutex_lock(&conn->fLockExpected);
|
||||
DoublyLinkedList<L2capFrame>::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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -4,6 +4,7 @@
|
||||
*/
|
||||
#include "L2capEndpoint.h"
|
||||
#include "l2cap_address.h"
|
||||
#include "l2cap_upper.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -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<L2capEndpoint*>(protocol);
|
||||
|
||||
delete protocol;
|
||||
// TODO: Some more checkins / uninit
|
||||
EndpointList.Remove(endpoint);
|
||||
|
||||
delete endpoint;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
#include <KernelExport.h>
|
||||
#include <string.h>
|
||||
#include <lock.h>
|
||||
|
||||
#include <NetBufferUtilities.h>
|
||||
|
||||
@ -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<l2cap_hdr_t> 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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user