- 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
|
||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user