- Implementation for sendto() & close(), tested over a Motorola V5
- Incomming command rejections not yet properly handled. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37486 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
#include "L2capEndpoint.h"
|
#include "L2capEndpoint.h"
|
||||||
#include "l2cap_address.h"
|
#include "l2cap_address.h"
|
||||||
#include "l2cap_upper.h"
|
#include "l2cap_upper.h"
|
||||||
|
#include "l2cap_lower.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -99,28 +100,36 @@ L2capEndpoint::Close()
|
|||||||
{
|
{
|
||||||
debugf("[%ld] %p\n", find_thread(NULL), this);
|
debugf("[%ld] %p\n", find_thread(NULL), this);
|
||||||
|
|
||||||
if (fEstablishSemaphore != -1) {
|
if (fChannel == NULL) {
|
||||||
debugf("server socket not handling any channel %p\n", this);
|
// TODO: Parent socket
|
||||||
|
|
||||||
delete_sem(fEstablishSemaphore);
|
|
||||||
// TODO: Clean needed stuff
|
|
||||||
// Unbind?
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Client endpoint
|
// Child Socket
|
||||||
if (fState == CLOSING) {
|
if (fState == CLOSED) {
|
||||||
debugf("Already closed by peer %p\n", this);
|
debugf("Already closed by peer %p\n", this);
|
||||||
// TODO: Clean needed stuff
|
// TODO: Clean needed stuff
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
} else {
|
} else {
|
||||||
// Issue Disconnection request over the channel
|
// Issue Disconnection request over the channel
|
||||||
fState = CLOSED;
|
MarkClosed();
|
||||||
return l2cap_upper_dis_req(fChannel);
|
|
||||||
|
bigtime_t timeout = absolute_timeout(300 * 1000 * 1000);
|
||||||
|
|
||||||
|
status_t error = l2cap_upper_dis_req(fChannel);
|
||||||
|
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
return acquire_sem_etc(fEstablishSemaphore, 1,
|
||||||
|
B_ABSOLUTE_TIMEOUT | B_CAN_INTERRUPT, timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fEstablishSemaphore != -1) {
|
||||||
|
delete_sem(fEstablishSemaphore);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -351,6 +360,25 @@ L2capEndpoint::ReadData(size_t numBytes, uint32 flags, net_buffer** _buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
L2capEndpoint::SendData(net_buffer* buffer)
|
||||||
|
{
|
||||||
|
debugf("size=%ld\n", buffer->size);
|
||||||
|
|
||||||
|
if (fState != ESTABLISHED) {
|
||||||
|
debugf("Invalid State %p\n", this);
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
btCoreData->SpawnFrame(fChannel->conn, fChannel, buffer, L2CAP_B_FRAME);
|
||||||
|
|
||||||
|
SchedConnectionPurgeThread(fChannel->conn);
|
||||||
|
|
||||||
|
// TODO: Report bytes sent?
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
L2capEndpoint::Sendable()
|
L2capEndpoint::Sendable()
|
||||||
{
|
{
|
||||||
@@ -445,6 +473,7 @@ L2capEndpoint::MarkEstablished()
|
|||||||
fChannel->psm, fChannel->scid, fChannel->dcid);
|
fChannel->psm, fChannel->scid, fChannel->dcid);
|
||||||
|
|
||||||
fChannel->state = L2CAP_CHAN_OPEN;
|
fChannel->state = L2CAP_CHAN_OPEN;
|
||||||
|
fState = ESTABLISHED;
|
||||||
|
|
||||||
if (fPeerEndpoint != NULL) {
|
if (fPeerEndpoint != NULL) {
|
||||||
|
|
||||||
@@ -465,8 +494,11 @@ status_t
|
|||||||
L2capEndpoint::MarkClosed()
|
L2capEndpoint::MarkClosed()
|
||||||
{
|
{
|
||||||
flowf("\n");
|
flowf("\n");
|
||||||
|
if (fState == CLOSED) {
|
||||||
|
release_sem(fEstablishSemaphore);
|
||||||
|
}
|
||||||
|
|
||||||
fState = CLOSED;
|
fState = CLOSED;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ public:
|
|||||||
struct sockaddr* _address, socklen_t* _addressLength);
|
struct sockaddr* _address, socklen_t* _addressLength);
|
||||||
|
|
||||||
ssize_t ReadData(size_t numBytes, uint32 flags, net_buffer** _buffer);
|
ssize_t ReadData(size_t numBytes, uint32 flags, net_buffer** _buffer);
|
||||||
|
ssize_t SendData(net_buffer* buffer);
|
||||||
ssize_t Sendable();
|
ssize_t Sendable();
|
||||||
ssize_t Receivable();
|
ssize_t Receivable();
|
||||||
|
|
||||||
|
|||||||
@@ -101,8 +101,12 @@ l2cap_open(net_protocol* protocol)
|
|||||||
status_t
|
status_t
|
||||||
l2cap_close(net_protocol* protocol)
|
l2cap_close(net_protocol* protocol)
|
||||||
{
|
{
|
||||||
|
L2capEndpoint* endpoint = static_cast<L2capEndpoint*>(protocol);
|
||||||
|
|
||||||
flowf("\n");
|
flowf("\n");
|
||||||
|
|
||||||
|
endpoint->Close();
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +214,10 @@ l2cap_send_data(net_protocol* protocol, net_buffer* buffer)
|
|||||||
{
|
{
|
||||||
flowf("\n");
|
flowf("\n");
|
||||||
|
|
||||||
return EOPNOTSUPP;
|
if (buffer == NULL)
|
||||||
|
return ENOBUFS;
|
||||||
|
|
||||||
|
return ((L2capEndpoint*)protocol)->SendData(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,15 @@ l2cap_receive(HciConnection* conn, net_buffer* buffer)
|
|||||||
uint16 dcid;
|
uint16 dcid;
|
||||||
uint16 length;
|
uint16 length;
|
||||||
|
|
||||||
|
#ifdef DUMP_L2CAP_FRAME
|
||||||
|
flowf("DUMP:");
|
||||||
|
for (uint i = 0; i < buffer->size; i++) {
|
||||||
|
uint8 c = 0;
|
||||||
|
gBufferModule->read(buffer, i, &c, 1);
|
||||||
|
dprintf("[%x]", c);
|
||||||
|
}
|
||||||
|
dprintf("\n");
|
||||||
|
#endif
|
||||||
// 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);
|
||||||
@@ -61,6 +70,8 @@ l2cap_receive(HciConnection* conn, net_buffer* buffer)
|
|||||||
length = bufferHeader->length = le16toh(bufferHeader->length);
|
length = bufferHeader->length = le16toh(bufferHeader->length);
|
||||||
dcid = bufferHeader->dcid = le16toh(bufferHeader->dcid);
|
dcid = bufferHeader->dcid = le16toh(bufferHeader->dcid);
|
||||||
|
|
||||||
|
debugf("len=%d cid=%x\n", length, dcid);
|
||||||
|
|
||||||
bufferHeader.Remove(); // pulling
|
bufferHeader.Remove(); // pulling
|
||||||
|
|
||||||
// Check payload size
|
// Check payload size
|
||||||
@@ -165,7 +176,8 @@ purge_connection(HciConnection* conn)
|
|||||||
} // TODO: someone put it
|
} // TODO: someone put it
|
||||||
|
|
||||||
|
|
||||||
debugf("code=%d frame %p tolower\n", frame->code, frame->buffer);
|
debugf("type=%d, code=%d frame %p tolower\n", frame->type, frame->code,
|
||||||
|
frame->buffer);
|
||||||
|
|
||||||
frame->buffer->type = conn->handle;
|
frame->buffer->type = conn->handle;
|
||||||
btDevices->PostACL(conn->ndevice->index, frame->buffer);
|
btDevices->PostACL(conn->ndevice->index, frame->buffer);
|
||||||
|
|||||||
@@ -120,19 +120,19 @@ l2cap_process_signal_cmd(HciConnection* conn, net_buffer* buffer)
|
|||||||
return ENOBUFS;
|
return ENOBUFS;
|
||||||
}
|
}
|
||||||
|
|
||||||
commandHeader->length = le16toh(commandHeader->length);
|
uint8 processingCode = commandHeader->code;
|
||||||
|
uint8 processingIdent = commandHeader->ident;
|
||||||
|
uint16 processingLength = le16toh(commandHeader->length);
|
||||||
|
|
||||||
/* Verify command length */
|
/* Verify command length */
|
||||||
if (buffer->size < commandHeader->length) {
|
if (buffer->size < processingLength) {
|
||||||
debugf("invalid L2CAP signaling command, code=%#x, ident=%d,"
|
debugf("invalid L2CAP signaling command, code=%#x, ident=%d,"
|
||||||
" length=%d, buffer size=%ld\n", commandHeader->code,
|
" length=%d, buffer size=%ld\n", processingCode,
|
||||||
commandHeader->ident, commandHeader->length, buffer->size);
|
processingIdent, processingLength, buffer->size);
|
||||||
gBufferModule->free(buffer);
|
gBufferModule->free(buffer);
|
||||||
return (EMSGSIZE);
|
return (EMSGSIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 processingCode = commandHeader->code;
|
|
||||||
uint16 processingIdent = commandHeader->ident;
|
|
||||||
|
|
||||||
commandHeader.Remove(); // pulling the header of the command
|
commandHeader.Remove(); // pulling the header of the command
|
||||||
|
|
||||||
@@ -761,7 +761,7 @@ l2cap_process_discon_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
|
|||||||
|
|
||||||
// inform upper if we were not actually already waiting
|
// inform upper if we were not actually already waiting
|
||||||
if (channel->state != L2CAP_CHAN_W4_L2CAP_DISCON_RSP) {
|
if (channel->state != L2CAP_CHAN_W4_L2CAP_DISCON_RSP) {
|
||||||
l2cap_l2ca_discon_ind(channel); // do not care about result
|
l2cap_discon_req_ind(channel); // do not care about result
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send L2CAP_DisconnectRsp */
|
/* Send L2CAP_DisconnectRsp */
|
||||||
@@ -773,8 +773,6 @@ l2cap_process_discon_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
|
|||||||
/* Link command to the queue */
|
/* Link command to the queue */
|
||||||
SchedConnectionPurgeThread(conn);
|
SchedConnectionPurgeThread(conn);
|
||||||
|
|
||||||
btCoreData->RemoveChannel(conn, channel->scid);
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
reject:
|
reject:
|
||||||
@@ -816,7 +814,7 @@ l2cap_process_discon_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Verify channel state, do nothing if invalid */
|
/* Verify channel state, do nothing if invalid */
|
||||||
if (cmd->channel->state != L2CAP_CHAN_W4_L2CAP_DISCON_RSP) {
|
if (cmd->channel->state != L2CAP_CHAN_W4_L2CA_DISCON_RSP) {
|
||||||
debugf("unexpected L2CAP_DisconnectRsp. Invalid state, cid=%d, "
|
debugf("unexpected L2CAP_DisconnectRsp. Invalid state, cid=%d, "
|
||||||
"state=%d\n", scid, cmd->channel->state);
|
"state=%d\n", scid, cmd->channel->state);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -839,7 +837,7 @@ l2cap_process_discon_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
|
|||||||
if ((error = btCoreData->UnTimeoutSignal(cmd)) != 0)
|
if ((error = btCoreData->UnTimeoutSignal(cmd)) != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
//INDICATION = ng_l2cap_l2ca_discon_rsp(cmd->channel, cmd->token, NG_L2CAP_SUCCESS);
|
l2cap_discon_rsp_ind(cmd->channel/* results? */);
|
||||||
btCoreData->RemoveChannel(conn, scid); /* this will free commands too */
|
btCoreData->RemoveChannel(conn, scid); /* this will free commands too */
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@@ -1015,6 +1013,8 @@ l2cap_process_cmd_rej(HciConnection* conn, uint8 ident, net_buffer* buffer)
|
|||||||
|
|
||||||
command->reason = le16toh(command->reason);
|
command->reason = le16toh(command->reason);
|
||||||
|
|
||||||
|
debugf("reason=%d\n", command->reason);
|
||||||
|
|
||||||
command.Remove();
|
command.Remove();
|
||||||
|
|
||||||
/* Check if we have pending command descriptor */
|
/* Check if we have pending command descriptor */
|
||||||
|
|||||||
@@ -209,12 +209,26 @@ l2cap_cfg_req_ind(L2capChannel* channel)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
l2cap_l2ca_discon_ind(L2capChannel* channel)
|
l2cap_discon_req_ind(L2capChannel* channel)
|
||||||
{
|
{
|
||||||
return channel->endpoint->MarkClosed();
|
return channel->endpoint->MarkClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
l2cap_discon_rsp_ind(L2capChannel* channel)
|
||||||
|
{
|
||||||
|
if (channel->state == L2CAP_CHAN_W4_L2CA_DISCON_RSP) {
|
||||||
|
channel->endpoint->MarkClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#pragma mark - Signals from Upper Layer
|
#pragma mark - Signals from Upper Layer
|
||||||
#endif
|
#endif
|
||||||
@@ -247,8 +261,8 @@ l2cap_upper_dis_req(L2capChannel* channel)
|
|||||||
{
|
{
|
||||||
channel->ident = btCoreData->ChannelAllocateIdent(channel->conn);
|
channel->ident = btCoreData->ChannelAllocateIdent(channel->conn);
|
||||||
|
|
||||||
net_buffer* buf = l2cap_discon_req(channel->ident, channel->scid,
|
net_buffer* buf = l2cap_discon_req(channel->ident, channel->dcid,
|
||||||
channel->dcid);
|
channel->scid);
|
||||||
L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf,
|
L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf,
|
||||||
channel->ident, L2CAP_DISCON_REQ);
|
channel->ident, L2CAP_DISCON_REQ);
|
||||||
if (cmd == NULL) {
|
if (cmd == NULL) {
|
||||||
@@ -273,7 +287,7 @@ l2cap_upper_dis_req(L2capChannel* channel)
|
|||||||
status_t
|
status_t
|
||||||
l2cap_co_receive(HciConnection* conn, net_buffer* buffer, uint16 dcid)
|
l2cap_co_receive(HciConnection* conn, net_buffer* buffer, uint16 dcid)
|
||||||
{
|
{
|
||||||
debugf("Handle %d To dcid %d\n", conn->handle, dcid);
|
debugf("Handle %d To dcid %x size=%ld\n", conn->handle, dcid, buffer->size);
|
||||||
|
|
||||||
L2capChannel* channel = btCoreData->ChannelBySourceID(conn, dcid);
|
L2capChannel* channel = btCoreData->ChannelBySourceID(conn, dcid);
|
||||||
|
|
||||||
@@ -306,3 +320,6 @@ l2cap_cl_receive(HciConnection* conn, net_buffer* buffer, uint16 psm)
|
|||||||
return gStackModule->fifo_enqueue_buffer(
|
return gStackModule->fifo_enqueue_buffer(
|
||||||
&endpoint->fReceivingFifo, buffer);
|
&endpoint->fReceivingFifo, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
|
|
||||||
status_t l2cap_l2ca_con_ind(L2capChannel* channel);
|
status_t l2cap_l2ca_con_ind(L2capChannel* channel);
|
||||||
status_t l2cap_cfg_req_ind(L2capChannel* channel);
|
status_t l2cap_cfg_req_ind(L2capChannel* channel);
|
||||||
status_t l2cap_l2ca_discon_ind(L2capChannel* channel);
|
status_t l2cap_discon_req_ind(L2capChannel* channel);
|
||||||
|
status_t l2cap_discon_rsp_ind(L2capChannel* channel);
|
||||||
|
|
||||||
status_t l2cap_con_rsp_ind(HciConnection* conn, L2capChannel* channel);
|
status_t l2cap_con_rsp_ind(HciConnection* conn, L2capChannel* channel);
|
||||||
status_t l2cap_cfg_rsp_ind(L2capChannel* channel);
|
status_t l2cap_cfg_rsp_ind(L2capChannel* channel);
|
||||||
|
|
||||||
@@ -17,6 +19,7 @@ status_t l2cap_upper_con_req(L2capChannel* channel);
|
|||||||
status_t l2cap_upper_dis_req(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);
|
||||||
status_t l2cap_cl_receive(HciConnection* conn, net_buffer* buffer, uint16 psm);
|
status_t l2cap_cl_receive(HciConnection* conn, net_buffer* buffer, uint16 psm);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user