- Implement hook Connect()

- Polish l2cap signals negotiation



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37472 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Oliver Ruiz Dorantes
2010-07-11 16:57:47 +00:00
parent f0cbfc95e0
commit ef36d96496
7 changed files with 223 additions and 92 deletions
@@ -35,7 +35,7 @@ L2capEndpoint::L2capEndpoint(net_socket* socket)
: :
ProtocolSocket(socket), ProtocolSocket(socket),
fConfigurationSet(false), fConfigurationSet(false),
fAcceptSemaphore(-1), fEstablishSemaphore(-1),
fPeerEndpoint(NULL), fPeerEndpoint(NULL),
fChannel(NULL) fChannel(NULL)
{ {
@@ -99,10 +99,10 @@ L2capEndpoint::Close()
{ {
debugf("[%ld] %p\n", find_thread(NULL), this); debugf("[%ld] %p\n", find_thread(NULL), this);
if (fAcceptSemaphore != -1) { if (fEstablishSemaphore != -1) {
debugf("server socket not handling any channel %p\n", this); debugf("server socket not handling any channel %p\n", this);
delete_sem(fAcceptSemaphore); delete_sem(fEstablishSemaphore);
// TODO: Clean needed stuff // TODO: Clean needed stuff
// Unbind? // Unbind?
return B_OK; return B_OK;
@@ -191,8 +191,8 @@ L2capEndpoint::Listen(int backlog)
return B_BAD_VALUE; return B_BAD_VALUE;
} }
fAcceptSemaphore = create_sem(0, "l2cap serv accept"); fEstablishSemaphore = create_sem(0, "l2cap serv accept");
if (fAcceptSemaphore < B_OK) { if (fEstablishSemaphore < B_OK) {
flowf("Semaphore could not be created\n"); flowf("Semaphore could not be created\n");
return ENOBUFS; return ENOBUFS;
} }
@@ -247,7 +247,19 @@ L2capEndpoint::Connect(const struct sockaddr* _address)
if (l2cap_upper_con_req(channel) == B_OK) { if (l2cap_upper_con_req(channel) == B_OK) {
fState = CONNECTING; fState = CONNECTING;
return B_OK; BindToChannel(channel);
fEstablishSemaphore = create_sem(0, "l2cap client");
if (fEstablishSemaphore < B_OK) {
flowf("Semaphore could not be created\n");
return ENOBUFS;
}
bigtime_t timeout = absolute_timeout(300 * 1000 * 1000);
return acquire_sem_etc(fEstablishSemaphore, 1,
B_ABSOLUTE_TIMEOUT | B_CAN_INTERRUPT, timeout);
} else { } else {
return ECONNREFUSED; return ECONNREFUSED;
} }
@@ -270,7 +282,7 @@ L2capEndpoint::Accept(net_socket** _acceptedSocket)
do { do {
// locker.Unlock(); // locker.Unlock();
status = acquire_sem_etc(fAcceptSemaphore, 1, B_ABSOLUTE_TIMEOUT status = acquire_sem_etc(fEstablishSemaphore, 1, B_ABSOLUTE_TIMEOUT
| B_CAN_INTERRUPT, timeout); | B_CAN_INTERRUPT, timeout);
if (status != B_OK) if (status != B_OK)
@@ -380,7 +392,7 @@ L2capEndpoint::ForPsm(uint16 psm)
void void
L2capEndpoint::BindToChannel(L2capChannel* channel) L2capEndpoint::BindNewEnpointToChannel(L2capChannel* channel)
{ {
net_socket* newSocket; net_socket* newSocket;
status_t error = gSocketModule->spawn_pending_socket(socket, &newSocket); status_t error = gSocketModule->spawn_pending_socket(socket, &newSocket);
@@ -411,18 +423,39 @@ L2capEndpoint::BindToChannel(L2capChannel* channel)
} }
void
L2capEndpoint::BindToChannel(L2capChannel* channel)
{
this->fChannel = channel;
channel->endpoint = this;
// Provide the channel the configuration set by the user socket
channel->configuration = &fConfiguration;
// no parent to give feedback
fPeerEndpoint = NULL;
}
status_t status_t
L2capEndpoint::MarkEstablished() L2capEndpoint::MarkEstablished()
{ {
status_t error = B_OK;
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);
status_t error = gSocketModule->set_connected(socket); fChannel->state = L2CAP_CHAN_OPEN;
if (error == B_OK) {
release_sem(fPeerEndpoint->fAcceptSemaphore); if (fPeerEndpoint != NULL) {
} else {
debugf("Could not set child Endpoint %p %s\n", this, strerror(error)); error = gSocketModule->set_connected(socket);
} if (error == B_OK) {
release_sem(fPeerEndpoint->fEstablishSemaphore);
} else {
debugf("Could not set child Endpoint %p %s\n", this, strerror(error));
}
} else
release_sem(fEstablishSemaphore);
return error; return error;
} }
@@ -65,6 +65,7 @@ public:
status_t Shutdown(int direction); status_t Shutdown(int direction);
void BindNewEnpointToChannel(L2capChannel* channel);
void BindToChannel(L2capChannel* channel); void BindToChannel(L2capChannel* channel);
status_t MarkEstablished(); status_t MarkEstablished();
status_t MarkClosed(); status_t MarkClosed();
@@ -102,7 +103,7 @@ private:
mutex fLock; mutex fLock;
State fState; State fState;
sem_id fAcceptSemaphore; sem_id fEstablishSemaphore;
L2capEndpoint* fPeerEndpoint; L2capEndpoint* fPeerEndpoint;
L2capChannel* fChannel; L2capChannel* fChannel;
@@ -155,7 +155,7 @@ l2cap_getsockopt(net_protocol* protocol, int level, int option,
{ {
flowf("\n"); flowf("\n");
return EOPNOTSUPP; return B_OK;
} }
@@ -167,7 +167,7 @@ l2cap_setsockopt(net_protocol* protocol, int level, int option,
((L2capEndpoint*)protocol)->fConfigurationSet = true; ((L2capEndpoint*)protocol)->fConfigurationSet = true;
return EOPNOTSUPP; return B_OK;
} }
@@ -210,7 +210,7 @@ l2cap_send_data(net_protocol* protocol, net_buffer* buffer)
{ {
flowf("\n"); flowf("\n");
return protocol->next->module->send_data(protocol->next, buffer); return EOPNOTSUPP;
} }
@@ -220,7 +220,7 @@ l2cap_send_routed_data(net_protocol* protocol, struct net_route* route,
{ {
flowf("\n"); flowf("\n");
return protocol->next->module->send_routed_data(protocol->next, route, buffer); return EOPNOTSUPP;
} }
@@ -27,6 +27,9 @@ l2cap_cfg_req(uint8 _ident, uint16 _dcid, uint16 _flags, net_buffer* _data);
net_buffer* net_buffer*
l2cap_cfg_rsp(uint8 _ident, uint16 _scid, uint16 _flags, uint16 _result, net_buffer* _data); l2cap_cfg_rsp(uint8 _ident, uint16 _scid, uint16 _flags, uint16 _result, net_buffer* _data);
net_buffer*
l2cap_build_cfg_options(uint16* _mtu, uint16* _flush_timo, l2cap_flow_t* _flow);
net_buffer* net_buffer*
l2cap_discon_req(uint8 _ident, uint16 _dcid, uint16 _scid); l2cap_discon_req(uint8 _ident, uint16 _dcid, uint16 _scid);
@@ -165,7 +165,7 @@ purge_connection(HciConnection* conn)
} // TODO: someone put it } // TODO: someone put it
debugf("dev %p frame %p tolower\n", conn->ndevice, frame->buffer); debugf("code=%d frame %p tolower\n", 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);
@@ -45,13 +45,13 @@ typedef enum _option_status {
l2cap_flow_t default_qos = { l2cap_flow_t default_qos = {
/* flags */ 0x0, /* flags */ 0x0,
/* service_type */ HCI_SERVICE_TYPE_BEST_EFFORT, /* service_type */ HCI_SERVICE_TYPE_BEST_EFFORT,
/* token_rate */ 0xffffffff, /* maximum */ /* token_rate */ 0xffffffff, /* maximum */
/* token_bucket_size */ 0xffffffff, /* maximum */ /* token_bucket_size */ 0xffffffff, /* maximum */
/* peak_bandwidth */ 0x00000000, /* maximum */ /* peak_bandwidth */ 0x00000000, /* maximum */
/* latency */ 0xffffffff, /* don't care */ /* latency */ 0xffffffff, /* don't care */
/* delay_variation */ 0xffffffff /* don't care */ /* delay_variation */ 0xffffffff /* don't care */
}; };
@@ -124,8 +124,9 @@ l2cap_process_signal_cmd(HciConnection* conn, net_buffer* buffer)
/* Verify command length */ /* Verify command length */
if (buffer->size < commandHeader->length) { if (buffer->size < commandHeader->length) {
debugf("invalid L2CAP signaling command, code=%#x, ident=%d, length=%d, buffer size=%ld\n", debugf("invalid L2CAP signaling command, code=%#x, ident=%d,"
commandHeader->code, commandHeader->ident, commandHeader->length, buffer->size); " length=%d, buffer size=%ld\n", commandHeader->code,
commandHeader->ident, commandHeader->length, buffer->size);
gBufferModule->free(buffer); gBufferModule->free(buffer);
return (EMSGSIZE); return (EMSGSIZE);
} }
@@ -186,8 +187,10 @@ l2cap_process_signal_cmd(HciConnection* conn, net_buffer* buffer)
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
/*send_l2cap_reject(con, processingIdent, L2CAP_REJ_NOT_UNDERSTOOD, 0, 0, 0);*/ // be rejected?
// send_l2cap_reject(con, processingIdent,
// L2CAP_REJ_NOT_UNDERSTOOD, 0, 0, 0);
gBufferModule->free(m); gBufferModule->free(m);
break; break;
} }
@@ -228,9 +231,8 @@ l2cap_process_con_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
command.Remove(); // pull the command body command.Remove(); // pull the command body
/* 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.
*/
channel = btCoreData->AddChannel(conn, psm /*, dcid, ident*/); channel = btCoreData->AddChannel(conn, psm /*, dcid, ident*/);
if (channel == NULL) { if (channel == NULL) {
flowf("No resources to create channel\n"); flowf("No resources to create channel\n");
@@ -245,7 +247,7 @@ l2cap_process_con_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
status_t indicationStatus = l2cap_l2ca_con_ind(channel); status_t indicationStatus = l2cap_l2ca_con_ind(channel);
if ( indicationStatus == B_OK ) { if ( indicationStatus == B_OK ) {
//channel->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, channel->scid, dcid, L2CAP_NO_RESOURCES);*/ /* send_l2cap_con_rej(con, ident, channel->scid, dcid, L2CAP_NO_RESOURCES);*/
@@ -279,22 +281,28 @@ l2cap_process_con_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
status = le16toh(command->status); status = le16toh(command->status);
command.Remove(); // pull the command body command.Remove(); // pull the command body
debugf("dcid=%d scid=%d result=%d status%d\n", dcid, scid, result, status);
/* Check if we have pending command descriptor */ /* Check if we have pending command descriptor */
cmd = btCoreData->SignalByIdent(conn, ident); cmd = btCoreData->SignalByIdent(conn, ident);
if (cmd == NULL) { if (cmd == NULL) {
debugf("unexpected L2CAP_ConnectRsp command. ident=%d, con_handle=%d\n", ident, conn->handle); debugf("unexpected L2CAP_ConnectRsp command. ident=%d, "
"con_handle=%d\n", ident, conn->handle);
return ENOENT; return ENOENT;
} }
/* Verify channel state, if invalid - do nothing */ /* Verify channel state, if invalid - do nothing */
if (cmd->channel->state != L2CAP_CHAN_W4_L2CAP_CON_RSP) { if (cmd->channel->state != L2CAP_CHAN_W4_L2CAP_CON_RSP) {
debugf("unexpected L2CAP_ConnectRsp. Invalid channel state, cid=%d, state=%d\n", scid, cmd->channel->state); debugf("unexpected L2CAP_ConnectRsp. Invalid channel state, "
"cid=%d, state=%d\n", scid, cmd->channel->state);
goto reject; goto reject;
} }
/* Verify CIDs and send reject if does not match */ /* Verify CIDs and send reject if does not match */
if (cmd->channel->scid != scid) { if (cmd->channel->scid != scid) {
debugf("unexpected L2CAP_ConnectRsp. Channel IDs do not match, scid=%d(%d)\n", cmd->channel->scid, scid); debugf("unexpected L2CAP_ConnectRsp. Channel IDs do not match, "
"scid=%d(%d)\n", cmd->channel->scid, scid);
goto reject; goto reject;
} }
@@ -318,9 +326,10 @@ l2cap_process_con_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
btCoreData->TimeoutSignal(cmd, bluetooth_l2cap_ertx_timeout); btCoreData->TimeoutSignal(cmd, bluetooth_l2cap_ertx_timeout);
// TODO: // TODO:
// INDICATION error = ng_l2cap_l2ca_con_rsp(cmd->channel, cmd->token, result, status); // INDICATION error = ng_l2cap_l2ca_con_rsp(cmd->channel, cmd->token,
// result, status);
// if (error != B_OK) // if (error != B_OK)
// btCoreData->RemoveChannel(conn, cmd->channel->scid); // btCoreData->RemoveChannel(conn, cmd->channel->scid);
} else { } else {
@@ -340,7 +349,8 @@ l2cap_process_con_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
/* XXX do we have to remove the channel on error? */ /* XXX do we have to remove the channel on error? */
if (error != 0 || result != L2CAP_SUCCESS) { if (error != 0 || result != L2CAP_SUCCESS) {
debugf("failed to open L2CAP channel, result=%d, status=%d\n", result, status); debugf("failed to open L2CAP channel, result=%d, status=%d\n",
result, status);
btCoreData->RemoveChannel(conn, cmd->channel->scid); btCoreData->RemoveChannel(conn, cmd->channel->scid);
} }
@@ -358,7 +368,8 @@ reject:
static option_status static option_status
getNextSignalOption(net_buffer* nbuf, size_t* off, l2cap_cfg_opt_t* hdr, l2cap_cfg_opt_val_t* val) getNextSignalOption(net_buffer* nbuf, size_t* off, l2cap_cfg_opt_t* hdr,
l2cap_cfg_opt_val_t* val)
{ {
int hint; int hint;
size_t len = nbuf->size - (*off); size_t len = nbuf->size - (*off);
@@ -383,12 +394,11 @@ getNextSignalOption(net_buffer* nbuf, size_t* off, l2cap_cfg_opt_t* hdr, l2cap_c
gBufferModule->read(nbuf, *off, val, L2CAP_OPT_MTU_SIZE); gBufferModule->read(nbuf, *off, val, L2CAP_OPT_MTU_SIZE);
val->mtu = le16toh(val->mtu); val->mtu = le16toh(val->mtu);
*off += L2CAP_OPT_MTU_SIZE; *off += L2CAP_OPT_MTU_SIZE;
flowf("mtu specified\n"); debugf("mtu %d specified\n", val->mtu);
break; break;
case L2CAP_OPT_FLUSH_TIMO: case L2CAP_OPT_FLUSH_TIMO:
if (hdr->length != L2CAP_OPT_FLUSH_TIMO_SIZE || if (hdr->length != L2CAP_OPT_FLUSH_TIMO_SIZE || len < hdr->length)
len < hdr->length)
return BAD_OPTION_LENGTH; return BAD_OPTION_LENGTH;
gBufferModule->read(nbuf, *off, val, L2CAP_OPT_FLUSH_TIMO_SIZE); gBufferModule->read(nbuf, *off, val, L2CAP_OPT_FLUSH_TIMO_SIZE);
@@ -437,11 +447,10 @@ l2cap_process_cfg_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
size_t off; size_t off;
status_t error = 0; status_t error = 0;
debugf("configuration=%ld\n", buffer->size); debugf("configuration=%ld\n", buffer->size);
/* Get command parameters */ /* Get command parameters */
NetBufferHeaderReader<l2cap_cfg_req_cp> command(buffer); NetBufferHeaderReader<l2cap_cfg_req_cp> command(buffer);
status_t status = command.Status(); status_t status = command.Status();
if (status < B_OK) { if (status < B_OK) {
return ENOBUFS; return ENOBUFS;
@@ -450,22 +459,26 @@ l2cap_process_cfg_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
dcid = le16toh(command->dcid); dcid = le16toh(command->dcid);
respond = L2CAP_OPT_CFLAG(le16toh(command->flags)); respond = L2CAP_OPT_CFLAG(le16toh(command->flags));
command.Remove(); // pull configuration header command.Remove(); // pull configuration header
/* Check if we have this channel and it is in valid state */ /* Check if we have this channel and it is in valid state */
channel = btCoreData->ChannelBySourceID(conn, dcid); channel = btCoreData->ChannelBySourceID(conn, dcid);
if (channel == NULL) { if (channel == NULL) {
debugf("unexpected L2CAP_ConfigReq command. Channel does not exist, cid=%d\n", dcid); debugf("unexpected L2CAP_ConfigReq command. "
"Channel does not exist, cid=%d\n", dcid);
goto reject; goto reject;
} }
/* Verify channel state */ /* Verify channel state */
if (channel->state != L2CAP_CHAN_CONFIG && channel->state != L2CAP_CHAN_OPEN) { if (channel->state != L2CAP_CHAN_CONFIG
debugf("unexpected L2CAP_ConfigReq. Invalid channel state, cid=%d, state=%d\n", dcid, channel->state); && channel->state != L2CAP_CHAN_OPEN) {
debugf("unexpected L2CAP_ConfigReq. Invalid channel state, "
"cid=%d, state=%d\n", dcid, channel->state);
goto reject; goto reject;
} }
if (channel->state == L2CAP_CHAN_OPEN) { /* Re-configuration */ if (channel->state == L2CAP_CHAN_OPEN) { /* Re-configuration */
channel->cfgState = 0; // Reset configuration state
channel->state = L2CAP_CHAN_CONFIG; channel->state = L2CAP_CHAN_CONFIG;
} }
@@ -486,7 +499,8 @@ l2cap_process_cfg_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
break; break;
case L2CAP_OPT_QOS: case L2CAP_OPT_QOS:
memcpy(&val.flow, &channel->configuration->iflow, sizeof(channel->configuration->iflow)); memcpy(&val.flow, &channel->configuration->iflow,
sizeof(channel->configuration->iflow));
break; break;
default: /* Ignore unknown hint option */ default: /* Ignore unknown hint option */
@@ -507,9 +521,11 @@ l2cap_process_cfg_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
} }
} }
debugf("Pulled %ld of configuration fields respond=%d remaining=%ld\n", off, respond, buffer->size); debugf("Pulled %ld of configuration fields respond=%d remaining=%ld\n",
off, respond, buffer->size);
gBufferModule->remove_header(buffer, off); gBufferModule->remove_header(buffer, off);
/* /*
* Now check and see if we have to respond. If everything was OK then * Now check and see if we have to respond. If everything was OK then
* respond contain "C flag" and (if set) we will respond with empty * respond contain "C flag" and (if set) we will respond with empty
@@ -527,7 +543,7 @@ l2cap_process_cfg_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
error = send_l2cap_cfg_rsp(conn, ident, channel->dcid, result, buffer); error = send_l2cap_cfg_rsp(conn, ident, channel->dcid, result, buffer);
if (error != 0) { if (error != 0) {
// TODO: // TODO:
//INDICATION ng_l2cap_l2ca_discon_ind(ch); // INDICATION ng_l2cap_l2ca_discon_ind(ch);
btCoreData->RemoveChannel(conn, channel->scid); btCoreData->RemoveChannel(conn, channel->scid);
} }
} else { } else {
@@ -553,9 +569,9 @@ reject:
/* Process L2CAP_ConfigRsp command */ /* Process L2CAP_ConfigRsp command */
static status_t static status_t
l2cap_process_cfg_rsp(HciConnection *conn, uint8 ident, net_buffer *buffer) l2cap_process_cfg_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
{ {
L2capFrame *cmd = NULL; L2capFrame* cmd = NULL;
uint16 scid, cflag, result; uint16 scid, cflag, result;
l2cap_cfg_opt_t hdr; l2cap_cfg_opt_t hdr;
@@ -564,7 +580,7 @@ l2cap_process_cfg_rsp(HciConnection *conn, uint8 ident, net_buffer *buffer)
size_t off; size_t off;
status_t error = 0; status_t error = 0;
NetBufferHeaderReader<l2cap_cfg_rsp_cp> command(buffer); NetBufferHeaderReader<l2cap_cfg_rsp_cp> command(buffer);
status_t status = command.Status(); status_t status = command.Status();
if (status < B_OK) { if (status < B_OK) {
return ENOBUFS; return ENOBUFS;
@@ -576,23 +592,28 @@ l2cap_process_cfg_rsp(HciConnection *conn, uint8 ident, net_buffer *buffer)
command.Remove(); command.Remove();
debugf("scid=%d cflag=%d result=%d\n", scid, cflag, result);
/* Check if we have this command */ /* Check if we have this command */
cmd = btCoreData->SignalByIdent(conn, ident); cmd = btCoreData->SignalByIdent(conn, ident);
if (cmd == NULL) { if (cmd == NULL) {
debugf("unexpected L2CAP_ConfigRsp command. ident=%d, con_handle=%d\n", ident, conn->handle); debugf("unexpected L2CAP_ConfigRsp command. ident=%d, con_handle=%d\n",
ident, conn->handle);
gBufferModule->free(buffer); gBufferModule->free(buffer);
return ENOENT; return ENOENT;
} }
/* Verify CIDs and send reject if does not match */ /* Verify CIDs and send reject if does not match */
if (cmd->channel->scid != scid) { if (cmd->channel->scid != scid) {
debugf("unexpected L2CAP_ConfigRsp.Channel ID does not match, scid=%d(%d)\n", cmd->channel->scid, scid); debugf("unexpected L2CAP_ConfigRsp.Channel ID does not match, "
"scid=%d(%d)\n", cmd->channel->scid, scid);
goto reject; goto reject;
} }
/* Verify channel state and reject if invalid */ /* Verify channel state and reject if invalid */
if (cmd->channel->state != L2CAP_CHAN_CONFIG) { if (cmd->channel->state != L2CAP_CHAN_CONFIG) {
debugf("unexpected L2CAP_ConfigRsp. Invalid channel state, scid=%d, state=%d\n", cmd->channel->scid, cmd->channel->state); debugf("unexpected L2CAP_ConfigRsp. Invalid channel state, scid=%d, "
"state=%d\n", cmd->channel->scid, cmd->channel->state);
goto reject; goto reject;
} }
@@ -628,7 +649,7 @@ l2cap_process_cfg_rsp(HciConnection *conn, uint8 ident, net_buffer *buffer)
case L2CAP_OPT_QOS: case L2CAP_OPT_QOS:
memcpy(&val.flow, &cmd->channel->configuration->oflow, memcpy(&val.flow, &cmd->channel->configuration->oflow,
sizeof(cmd->channel->configuration->oflow)); sizeof(cmd->channel->configuration->oflow));
break; break;
default: /* Ignore unknown hint option */ default: /* Ignore unknown hint option */
@@ -643,8 +664,8 @@ l2cap_process_cfg_rsp(HciConnection *conn, uint8 ident, net_buffer *buffer)
* upper layer know and do not wait for more options. * upper layer know and do not wait for more options.
*/ */
debugf("failed to parse configuration options, error=%ld\n", error); debugf("fail parsing configuration options, error=%ld\n", error);
//INDICATION // INDICATION
result = L2CAP_UNKNOWN; result = L2CAP_UNKNOWN;
cflag = 0; cflag = 0;
@@ -709,13 +730,14 @@ l2cap_process_discon_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
channel = btCoreData->ChannelBySourceID(conn, dcid); channel = btCoreData->ChannelBySourceID(conn, dcid);
if (channel == 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=%x\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 (channel->state != L2CAP_CHAN_OPEN && channel->state != L2CAP_CHAN_CONFIG && if (channel->state != L2CAP_CHAN_OPEN
channel->state != L2CAP_CHAN_W4_L2CAP_DISCON_RSP) { && channel->state != L2CAP_CHAN_CONFIG
&& 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, channel->state); "state=%d\n", dcid, channel->state);
goto reject; goto reject;
@@ -788,20 +810,23 @@ l2cap_process_discon_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
/* Check if we have pending command descriptor */ /* Check if we have pending command descriptor */
cmd = btCoreData->SignalByIdent(conn, ident); cmd = btCoreData->SignalByIdent(conn, ident);
if (cmd == NULL) { if (cmd == NULL) {
debugf("unexpected L2CAP_DisconnectRsp command. ident=%d, con_handle=%d\n", ident, conn->handle); debugf("unexpected L2CAP_DisconnectRsp command. ident=%d, "
"con_handle=%d\n", ident, conn->handle);
goto out; goto out;
} }
/* 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_L2CAP_DISCON_RSP) {
debugf("unexpected L2CAP_DisconnectRsp. Invalid channel state, cid=%d, state=%d\n", scid, cmd->channel->state); debugf("unexpected L2CAP_DisconnectRsp. Invalid state, cid=%d, "
"state=%d\n", scid, cmd->channel->state);
goto out; goto out;
} }
/* Verify CIDs and send reject if does not match */ /* Verify CIDs and send reject if does not match */
if (cmd->channel->scid != scid || cmd->channel->dcid != dcid) { if (cmd->channel->scid != scid || cmd->channel->dcid != dcid) {
debugf("unexpected L2CAP_DisconnectRsp. Channel IDs do not match, scid=%d(%d), dcid=%d(%d)\n", debugf("unexpected L2CAP_DisconnectRsp. Channel IDs do not match, "
cmd->channel->scid, scid, cmd->channel->dcid, dcid); "scid=%d(%d), dcid=%d(%d)\n", cmd->channel->scid, scid,
cmd->channel->dcid, dcid);
goto out; goto out;
} }
@@ -827,7 +852,8 @@ l2cap_process_echo_req(HciConnection *conn, uint8 ident, net_buffer *buffer)
{ {
L2capFrame* cmd = NULL; L2capFrame* cmd = NULL;
cmd = btCoreData->SpawnSignal(conn, NULL, l2cap_echo_req(ident, NULL, 0), ident, L2CAP_ECHO_RSP); cmd = btCoreData->SpawnSignal(conn, NULL, l2cap_echo_req(ident, NULL, 0),
ident, L2CAP_ECHO_RSP);
if (cmd == NULL) { if (cmd == NULL) {
gBufferModule->free(buffer); gBufferModule->free(buffer);
return ENOMEM; return ENOMEM;
@@ -845,7 +871,7 @@ static status_t
l2cap_process_echo_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer) l2cap_process_echo_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
{ {
L2capFrame* cmd = NULL; L2capFrame* cmd = NULL;
status_t error = 0; status_t error = 0;
/* Check if we have this command */ /* Check if we have this command */
cmd = btCoreData->SignalByIdent(conn, ident); cmd = btCoreData->SignalByIdent(conn, ident);
@@ -855,12 +881,13 @@ l2cap_process_echo_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
return error; return error;
} }
// INDICATION error = ng_l2cap_l2ca_ping_rsp(cmd->conn, cmd->token,
//INDICATION error = ng_l2cap_l2ca_ping_rsp(cmd->conn, cmd->token, L2CAP_SUCCESS, conn->rx_pkt); // L2CAP_SUCCESS, conn->rx_pkt);
btCoreData->AcknowledgeSignal(cmd); btCoreData->AcknowledgeSignal(cmd);
} else { } else {
debugf("unexpected L2CAP_EchoRsp command. Requested ident does not exist, ident=%d\n", ident); debugf("unexpected L2CAP_EchoRsp command. ident does not exist, "
"ident=%d\n", ident);
gBufferModule->free(buffer); gBufferModule->free(buffer);
error = B_ERROR; error = B_ERROR;
} }
@@ -875,7 +902,7 @@ l2cap_process_info_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
{ {
L2capFrame* cmd = NULL; L2capFrame* cmd = NULL;
net_buffer* buf = NULL; net_buffer* buf = NULL;
uint16 type; uint16 type;
/* Get command parameters */ /* Get command parameters */
NetBufferHeaderReader<l2cap_info_req_cp> command(buffer); NetBufferHeaderReader<l2cap_info_req_cp> command(buffer);
@@ -884,14 +911,17 @@ l2cap_process_info_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
return ENOBUFS; return ENOBUFS;
} }
//command->type = le16toh(mtod(conn->rx_pkt, ng_l2cap_info_req_cp *)->type); // ??
// command->type = le16toh(mtod(conn->rx_pkt,
// ng_l2cap_info_req_cp *)->type);
type = le16toh(command->type); type = le16toh(command->type);
command.Remove(); command.Remove();
switch (type) { switch (type) {
case L2CAP_CONNLESS_MTU: case L2CAP_CONNLESS_MTU:
buf = l2cap_info_rsp(ident, L2CAP_CONNLESS_MTU, L2CAP_SUCCESS, L2CAP_MTU_DEFAULT); buf = l2cap_info_rsp(ident, L2CAP_CONNLESS_MTU, L2CAP_SUCCESS,
L2CAP_MTU_DEFAULT);
break; break;
default: default:
@@ -919,7 +949,7 @@ l2cap_process_info_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
status_t error = B_OK; status_t error = B_OK;
/* Get command parameters */ /* Get command parameters */
NetBufferHeaderReader<l2cap_info_rsp_cp> command(buffer); NetBufferHeaderReader<l2cap_info_rsp_cp> command(buffer);
status_t status = command.Status(); status_t status = command.Status();
if (status < B_OK) { if (status < B_OK) {
return ENOBUFS; return ENOBUFS;
@@ -933,7 +963,8 @@ l2cap_process_info_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
/* Check if we have pending command descriptor */ /* Check if we have pending command descriptor */
cmd = btCoreData->SignalByIdent(conn, ident); cmd = btCoreData->SignalByIdent(conn, ident);
if (cmd == NULL) { if (cmd == NULL) {
debugf("unexpected L2CAP_InfoRsp command. Requested ident does not exist, ident=%d\n", ident); debugf("unexpected L2CAP_InfoRsp command. Requested ident does not "
"exist, ident=%d\n", ident);
gBufferModule->free(buffer); gBufferModule->free(buffer);
return ENOENT; return ENOENT;
} }
@@ -1007,7 +1038,7 @@ l2cap_process_cmd_rej(HciConnection* conn, uint8 ident, net_buffer* buffer)
break; break;
case L2CAP_DISCON_REQ: case L2CAP_DISCON_REQ:
//INDICATION l2cap_l2ca_discon_rsp(cmd->channel,cmd->token,cp->reason); //INDICATION l2cap_l2ca_discon_rsp(cmd->channel, cmd->token, cp->reason);
btCoreData->RemoveChannel(conn, cmd->channel->scid); btCoreData->RemoveChannel(conn, cmd->channel->scid);
break; break;
@@ -1020,7 +1051,7 @@ l2cap_process_cmd_rej(HciConnection* conn, uint8 ident, net_buffer* buffer)
break; break;
default: default:
debugf("unexpected L2CAP_CommandRej. Unexpected L2CAP command opcode=%d\n", cmd->code); debugf("unexpected L2CAP_CommandRej. Unexpected opcode=%d\n", cmd->code);
break; break;
} }
@@ -1040,11 +1071,12 @@ l2cap_process_cmd_rej(HciConnection* conn, uint8 ident, net_buffer* buffer)
status_t status_t
send_l2cap_reject(HciConnection* conn, uint8 ident, uint16 reason, send_l2cap_reject(HciConnection* conn, uint8 ident, uint16 reason,
uint16 mtu, uint16 scid, uint16 dcid) uint16 mtu, uint16 scid, uint16 dcid)
{ {
L2capFrame* cmd = NULL; L2capFrame* cmd = NULL;
cmd = btCoreData->SpawnSignal(conn, NULL, l2cap_cmd_rej(ident, reason, mtu, scid, dcid), ident, L2CAP_CMD_REJ); cmd = btCoreData->SpawnSignal(conn, NULL, l2cap_cmd_rej(ident, reason,
mtu, scid, dcid), ident, L2CAP_CMD_REJ);
if (cmd == NULL) if (cmd == NULL)
return ENOMEM; return ENOMEM;
@@ -1056,11 +1088,13 @@ send_l2cap_reject(HciConnection* conn, uint8 ident, uint16 reason,
status_t status_t
send_l2cap_con_rej(HciConnection* conn, uint8 ident, uint16 scid, uint16 dcid, uint16 result) send_l2cap_con_rej(HciConnection* conn, uint8 ident, uint16 scid, uint16 dcid,
uint16 result)
{ {
L2capFrame* cmd = NULL; L2capFrame* cmd = NULL;
cmd = btCoreData->SpawnSignal(conn, NULL, l2cap_con_rsp(ident, scid, dcid, result, 0), ident, L2CAP_CON_RSP); cmd = btCoreData->SpawnSignal(conn, NULL,
l2cap_con_rsp(ident, scid, dcid, result, 0), ident, L2CAP_CON_RSP);
if (cmd == NULL) if (cmd == NULL)
return ENOMEM; return ENOMEM;
@@ -1072,12 +1106,13 @@ send_l2cap_con_rej(HciConnection* conn, uint8 ident, uint16 scid, uint16 dcid, u
status_t status_t
send_l2cap_cfg_rsp(HciConnection* conn, uint8 ident, uint16 scid, uint16 result, net_buffer* opt) send_l2cap_cfg_rsp(HciConnection* conn, uint8 ident, uint16 scid,
uint16 result, net_buffer* opt)
{ {
L2capFrame* cmd = NULL; L2capFrame* cmd = NULL;
cmd = btCoreData->SpawnSignal(conn, NULL, l2cap_cfg_rsp(ident, scid, 0, result, opt), cmd = btCoreData->SpawnSignal(conn, NULL,
ident, L2CAP_CFG_RSP); l2cap_cfg_rsp(ident, scid, 0, result, opt), ident, L2CAP_CFG_RSP);
if (cmd == NULL) { if (cmd == NULL) {
gBufferModule->free(opt); gBufferModule->free(opt);
return ENOMEM; return ENOMEM;
@@ -35,7 +35,7 @@ l2cap_l2ca_con_ind(L2capChannel* channel)
} }
// Pair Channel with endpoint // Pair Channel with endpoint
endpoint->BindToChannel(channel); endpoint->BindNewEnpointToChannel(channel);
net_buffer* buf = l2cap_con_rsp(channel->ident, channel->scid, channel->dcid, net_buffer* buf = l2cap_con_rsp(channel->ident, channel->scid, channel->dcid,
L2CAP_SUCCESS, L2CAP_NO_INFO); L2CAP_SUCCESS, L2CAP_NO_INFO);
@@ -58,13 +58,74 @@ l2cap_l2ca_con_ind(L2capChannel* channel)
status_t status_t
l2cap_con_rsp_ind(HciConnection* conn, L2capChannel* channel) l2cap_con_rsp_ind(HciConnection* conn, L2capChannel* channel)
{ {
uint16* flush_timo = NULL;
uint16* mtu = NULL;
l2cap_flow_t* flow = NULL;
flowf("\n"); flowf("\n");
// We received a configuration response, connection process // We received a configuration response, connection process
// is a step further but still configuration pending // is a step further but still configuration pending
// Check channel state
if (channel->state != L2CAP_CHAN_OPEN && channel->state != L2CAP_CHAN_CONFIG) {
debugf("unexpected L2CA_Config request message. Invalid channel" \
" state, state=%d, lcid=%d\n", channel->state, channel->scid);
return EINVAL;
}
// Set requested channel configuration options
net_buffer* options = NULL;
if (channel->endpoint->fConfigurationSet) {
// Compare channel settings with defaults
if (channel->configuration->imtu != L2CAP_MTU_DEFAULT)
mtu = &channel->configuration->imtu;
if (channel->configuration->flush_timo != L2CAP_FLUSH_TIMO_DEFAULT)
flush_timo = &channel->configuration->flush_timo;
if (memcmp(&default_qos, &channel->configuration->oflow,
sizeof(channel->configuration->oflow)) != 0)
flow = &channel->configuration->oflow;
// Create configuration options
if (mtu != NULL || flush_timo != NULL || flow!=NULL)
options = l2cap_build_cfg_options(mtu, flush_timo, flow);
if (options == NULL)
return ENOBUFS;
}
// Send Configuration Request // Send Configuration Request
// Create L2CAP command descriptor
channel->ident = btCoreData->ChannelAllocateIdent(conn);
if (channel->ident == L2CAP_NULL_IDENT)
return EIO;
net_buffer* buffer = l2cap_cfg_req(channel->ident, channel->dcid, 0, options);
if (buffer == NULL)
return ENOBUFS;
L2capFrame* command = btCoreData->SpawnSignal(conn, channel, buffer,
channel->ident, L2CAP_CFG_REQ);
if (command == NULL) {
gBufferModule->free(buffer);
channel->state = L2CAP_CHAN_CLOSED;
return ENOMEM;
}
channel->cfgState |= L2CAP_CFG_IN_SENT;
/* Adjust channel state for re-configuration */
if (channel->state == L2CAP_CHAN_OPEN) {
channel->state = L2CAP_CHAN_CONFIG;
channel->cfgState = 0;
}
flowf("Sending cfg req\n");
// Link command to the queue
SchedConnectionPurgeThread(channel->conn);
return B_OK; return B_OK;
} }
@@ -74,7 +135,6 @@ l2cap_cfg_rsp_ind(L2capChannel* channel)
{ {
channel->cfgState |= L2CAP_CFG_OUT; channel->cfgState |= L2CAP_CFG_OUT;
if ((channel->cfgState & L2CAP_CFG_BOTH) == L2CAP_CFG_BOTH) { if ((channel->cfgState & L2CAP_CFG_BOTH) == L2CAP_CFG_BOTH) {
channel->state = L2CAP_CHAN_OPEN;
return channel->endpoint->MarkEstablished(); return channel->endpoint->MarkEstablished();
} }
@@ -116,10 +176,9 @@ l2cap_cfg_req_ind(L2capChannel* channel)
if ((channel->cfgState & L2CAP_CFG_BOTH) == L2CAP_CFG_BOTH) { if ((channel->cfgState & L2CAP_CFG_BOTH) == L2CAP_CFG_BOTH) {
// Channel can be declared open // Channel can be declared open
channel->state = L2CAP_CHAN_OPEN;
channel->endpoint->MarkEstablished(); channel->endpoint->MarkEstablished();
} else { } else if ((channel->cfgState & L2CAP_CFG_IN_SENT) == 0) {
// send configuration Request by our side // send configuration Request by our side
if (channel->endpoint->RequiresConfiguration()) { if (channel->endpoint->RequiresConfiguration()) {
// TODO: define complete configuration packet // TODO: define complete configuration packet