- 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

View File

@ -35,7 +35,7 @@ L2capEndpoint::L2capEndpoint(net_socket* socket)
:
ProtocolSocket(socket),
fConfigurationSet(false),
fAcceptSemaphore(-1),
fEstablishSemaphore(-1),
fPeerEndpoint(NULL),
fChannel(NULL)
{
@ -99,10 +99,10 @@ L2capEndpoint::Close()
{
debugf("[%ld] %p\n", find_thread(NULL), this);
if (fAcceptSemaphore != -1) {
if (fEstablishSemaphore != -1) {
debugf("server socket not handling any channel %p\n", this);
delete_sem(fAcceptSemaphore);
delete_sem(fEstablishSemaphore);
// TODO: Clean needed stuff
// Unbind?
return B_OK;
@ -191,8 +191,8 @@ L2capEndpoint::Listen(int backlog)
return B_BAD_VALUE;
}
fAcceptSemaphore = create_sem(0, "l2cap serv accept");
if (fAcceptSemaphore < B_OK) {
fEstablishSemaphore = create_sem(0, "l2cap serv accept");
if (fEstablishSemaphore < B_OK) {
flowf("Semaphore could not be created\n");
return ENOBUFS;
}
@ -247,7 +247,19 @@ L2capEndpoint::Connect(const struct sockaddr* _address)
if (l2cap_upper_con_req(channel) == B_OK) {
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 {
return ECONNREFUSED;
}
@ -270,7 +282,7 @@ L2capEndpoint::Accept(net_socket** _acceptedSocket)
do {
// locker.Unlock();
status = acquire_sem_etc(fAcceptSemaphore, 1, B_ABSOLUTE_TIMEOUT
status = acquire_sem_etc(fEstablishSemaphore, 1, B_ABSOLUTE_TIMEOUT
| B_CAN_INTERRUPT, timeout);
if (status != B_OK)
@ -380,7 +392,7 @@ L2capEndpoint::ForPsm(uint16 psm)
void
L2capEndpoint::BindToChannel(L2capChannel* channel)
L2capEndpoint::BindNewEnpointToChannel(L2capChannel* channel)
{
net_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
L2capEndpoint::MarkEstablished()
{
status_t error = B_OK;
debugf("Endpoint %p for psm %d, schannel %x dchannel %x\n", this,
fChannel->psm, fChannel->scid, fChannel->dcid);
status_t error = gSocketModule->set_connected(socket);
fChannel->state = L2CAP_CHAN_OPEN;
if (fPeerEndpoint != NULL) {
error = gSocketModule->set_connected(socket);
if (error == B_OK) {
release_sem(fPeerEndpoint->fAcceptSemaphore);
release_sem(fPeerEndpoint->fEstablishSemaphore);
} else {
debugf("Could not set child Endpoint %p %s\n", this, strerror(error));
}
} else
release_sem(fEstablishSemaphore);
return error;
}

View File

@ -65,6 +65,7 @@ public:
status_t Shutdown(int direction);
void BindNewEnpointToChannel(L2capChannel* channel);
void BindToChannel(L2capChannel* channel);
status_t MarkEstablished();
status_t MarkClosed();
@ -102,7 +103,7 @@ private:
mutex fLock;
State fState;
sem_id fAcceptSemaphore;
sem_id fEstablishSemaphore;
L2capEndpoint* fPeerEndpoint;
L2capChannel* fChannel;

View File

@ -155,7 +155,7 @@ l2cap_getsockopt(net_protocol* protocol, int level, int option,
{
flowf("\n");
return EOPNOTSUPP;
return B_OK;
}
@ -167,7 +167,7 @@ l2cap_setsockopt(net_protocol* protocol, int level, int option,
((L2capEndpoint*)protocol)->fConfigurationSet = true;
return EOPNOTSUPP;
return B_OK;
}
@ -210,7 +210,7 @@ l2cap_send_data(net_protocol* protocol, net_buffer* buffer)
{
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");
return protocol->next->module->send_routed_data(protocol->next, route, buffer);
return EOPNOTSUPP;
}

View File

@ -27,6 +27,9 @@ l2cap_cfg_req(uint8 _ident, uint16 _dcid, uint16 _flags, net_buffer* _data);
net_buffer*
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*
l2cap_discon_req(uint8 _ident, uint16 _dcid, uint16 _scid);

View File

@ -165,7 +165,7 @@ purge_connection(HciConnection* conn)
} // 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;
btDevices->PostACL(conn->ndevice->index, frame->buffer);

View File

@ -124,8 +124,9 @@ l2cap_process_signal_cmd(HciConnection* conn, net_buffer* buffer)
/* Verify command length */
if (buffer->size < commandHeader->length) {
debugf("invalid L2CAP signaling command, code=%#x, ident=%d, length=%d, buffer size=%ld\n",
commandHeader->code, commandHeader->ident, commandHeader->length, buffer->size);
debugf("invalid L2CAP signaling command, code=%#x, ident=%d,"
" length=%d, buffer size=%ld\n", commandHeader->code,
commandHeader->ident, commandHeader->length, buffer->size);
gBufferModule->free(buffer);
return (EMSGSIZE);
}
@ -186,8 +187,10 @@ l2cap_process_signal_cmd(HciConnection* conn, net_buffer* buffer)
processingCode, processingIdent);
// Send L2CAP_CommandRej. Do not really care about the result
// ORD: Remiaining commands in the same packet are also to be rejected
/*send_l2cap_reject(con, processingIdent, L2CAP_REJ_NOT_UNDERSTOOD, 0, 0, 0);*/
// ORD: Remiaining commands in the same packet are also to
// be rejected?
// send_l2cap_reject(con, processingIdent,
// L2CAP_REJ_NOT_UNDERSTOOD, 0, 0, 0);
gBufferModule->free(m);
break;
}
@ -228,9 +231,8 @@ l2cap_process_con_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
command.Remove(); // pull the command body
/* Create new channel and send L2CA_ConnectInd
notification to the upper layer protocol.
*/
// Create new channel and send L2CA_ConnectInd
// notification to the upper layer protocol.
channel = btCoreData->AddChannel(conn, psm /*, dcid, ident*/);
if (channel == NULL) {
flowf("No resources to create channel\n");
@ -279,22 +281,28 @@ l2cap_process_con_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
status = le16toh(command->status);
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 */
cmd = btCoreData->SignalByIdent(conn, ident);
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;
}
/* Verify channel state, if invalid - do nothing */
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;
}
/* Verify CIDs and send reject if does not match */
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;
}
@ -318,7 +326,8 @@ l2cap_process_con_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
btCoreData->TimeoutSignal(cmd, bluetooth_l2cap_ertx_timeout);
// 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)
// btCoreData->RemoveChannel(conn, cmd->channel->scid);
@ -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? */
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);
}
@ -358,7 +368,8 @@ reject:
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;
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);
val->mtu = le16toh(val->mtu);
*off += L2CAP_OPT_MTU_SIZE;
flowf("mtu specified\n");
debugf("mtu %d specified\n", val->mtu);
break;
case L2CAP_OPT_FLUSH_TIMO:
if (hdr->length != L2CAP_OPT_FLUSH_TIMO_SIZE ||
len < hdr->length)
if (hdr->length != L2CAP_OPT_FLUSH_TIMO_SIZE || len < hdr->length)
return BAD_OPTION_LENGTH;
gBufferModule->read(nbuf, *off, val, L2CAP_OPT_FLUSH_TIMO_SIZE);
@ -437,7 +447,6 @@ l2cap_process_cfg_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
size_t off;
status_t error = 0;
debugf("configuration=%ld\n", buffer->size);
/* Get command parameters */
@ -455,17 +464,21 @@ l2cap_process_cfg_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
/* Check if we have this channel and it is in valid state */
channel = btCoreData->ChannelBySourceID(conn, dcid);
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;
}
/* Verify channel state */
if (channel->state != L2CAP_CHAN_CONFIG && channel->state != L2CAP_CHAN_OPEN) {
debugf("unexpected L2CAP_ConfigReq. Invalid channel state, cid=%d, state=%d\n", dcid, channel->state);
if (channel->state != L2CAP_CHAN_CONFIG
&& channel->state != L2CAP_CHAN_OPEN) {
debugf("unexpected L2CAP_ConfigReq. Invalid channel state, "
"cid=%d, state=%d\n", dcid, channel->state);
goto reject;
}
if (channel->state == L2CAP_CHAN_OPEN) { /* Re-configuration */
channel->cfgState = 0; // Reset configuration state
channel->state = L2CAP_CHAN_CONFIG;
}
@ -486,7 +499,8 @@ l2cap_process_cfg_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
break;
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;
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);
/*
* 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
@ -576,23 +592,28 @@ l2cap_process_cfg_rsp(HciConnection *conn, uint8 ident, net_buffer *buffer)
command.Remove();
debugf("scid=%d cflag=%d result=%d\n", scid, cflag, result);
/* Check if we have this command */
cmd = btCoreData->SignalByIdent(conn, ident);
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);
return ENOENT;
}
/* Verify CIDs and send reject if does not match */
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;
}
/* Verify channel state and reject if invalid */
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;
}
@ -643,7 +664,7 @@ l2cap_process_cfg_rsp(HciConnection *conn, uint8 ident, net_buffer *buffer)
* 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
result = L2CAP_UNKNOWN;
cflag = 0;
@ -709,13 +730,14 @@ l2cap_process_discon_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
channel = btCoreData->ChannelBySourceID(conn, dcid);
if (channel == NULL) {
debugf("unexpected L2CAP_DisconnectReq message.Channel does not exist, "
"cid=%d\n", dcid);
"cid=%x\n", dcid);
goto reject;
}
/* XXX Verify channel state and reject if invalid -- is that true? */
if (channel->state != L2CAP_CHAN_OPEN && channel->state != L2CAP_CHAN_CONFIG &&
channel->state != L2CAP_CHAN_W4_L2CAP_DISCON_RSP) {
if (channel->state != L2CAP_CHAN_OPEN
&& channel->state != L2CAP_CHAN_CONFIG
&& channel->state != L2CAP_CHAN_W4_L2CAP_DISCON_RSP) {
debugf("unexpected L2CAP_DisconnectReq. Invalid channel state, cid=%d, "
"state=%d\n", dcid, channel->state);
goto reject;
@ -788,20 +810,23 @@ l2cap_process_discon_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
/* Check if we have pending command descriptor */
cmd = btCoreData->SignalByIdent(conn, ident);
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;
}
/* Verify channel state, do nothing if invalid */
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;
}
/* Verify CIDs and send reject if does not match */
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",
cmd->channel->scid, scid, cmd->channel->dcid, dcid);
debugf("unexpected L2CAP_DisconnectRsp. Channel IDs do not match, "
"scid=%d(%d), dcid=%d(%d)\n", cmd->channel->scid, scid,
cmd->channel->dcid, dcid);
goto out;
}
@ -827,7 +852,8 @@ l2cap_process_echo_req(HciConnection *conn, uint8 ident, net_buffer *buffer)
{
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) {
gBufferModule->free(buffer);
return ENOMEM;
@ -855,12 +881,13 @@ l2cap_process_echo_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
return error;
}
//INDICATION error = ng_l2cap_l2ca_ping_rsp(cmd->conn, cmd->token, L2CAP_SUCCESS, conn->rx_pkt);
// INDICATION error = ng_l2cap_l2ca_ping_rsp(cmd->conn, cmd->token,
// L2CAP_SUCCESS, conn->rx_pkt);
btCoreData->AcknowledgeSignal(cmd);
} 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);
error = B_ERROR;
}
@ -884,14 +911,17 @@ l2cap_process_info_req(HciConnection* conn, uint8 ident, net_buffer* buffer)
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);
command.Remove();
switch (type) {
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;
default:
@ -933,7 +963,8 @@ l2cap_process_info_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer)
/* Check if we have pending command descriptor */
cmd = btCoreData->SignalByIdent(conn, ident);
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);
return ENOENT;
}
@ -1020,7 +1051,7 @@ l2cap_process_cmd_rej(HciConnection* conn, uint8 ident, net_buffer* buffer)
break;
default:
debugf("unexpected L2CAP_CommandRej. Unexpected L2CAP command opcode=%d\n", cmd->code);
debugf("unexpected L2CAP_CommandRej. Unexpected opcode=%d\n", cmd->code);
break;
}
@ -1044,7 +1075,8 @@ send_l2cap_reject(HciConnection* conn, uint8 ident, uint16 reason,
{
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)
return ENOMEM;
@ -1056,11 +1088,13 @@ send_l2cap_reject(HciConnection* conn, uint8 ident, uint16 reason,
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;
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)
return ENOMEM;
@ -1072,12 +1106,13 @@ send_l2cap_con_rej(HciConnection* conn, uint8 ident, uint16 scid, uint16 dcid, u
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;
cmd = btCoreData->SpawnSignal(conn, NULL, l2cap_cfg_rsp(ident, scid, 0, result, opt),
ident, L2CAP_CFG_RSP);
cmd = btCoreData->SpawnSignal(conn, NULL,
l2cap_cfg_rsp(ident, scid, 0, result, opt), ident, L2CAP_CFG_RSP);
if (cmd == NULL) {
gBufferModule->free(opt);
return ENOMEM;

View File

@ -35,7 +35,7 @@ l2cap_l2ca_con_ind(L2capChannel* channel)
}
// Pair Channel with endpoint
endpoint->BindToChannel(channel);
endpoint->BindNewEnpointToChannel(channel);
net_buffer* buf = l2cap_con_rsp(channel->ident, channel->scid, channel->dcid,
L2CAP_SUCCESS, L2CAP_NO_INFO);
@ -58,13 +58,74 @@ l2cap_l2ca_con_ind(L2capChannel* channel)
status_t
l2cap_con_rsp_ind(HciConnection* conn, L2capChannel* channel)
{
uint16* flush_timo = NULL;
uint16* mtu = NULL;
l2cap_flow_t* flow = NULL;
flowf("\n");
// We received a configuration response, connection process
// 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
// 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;
}
@ -74,7 +135,6 @@ l2cap_cfg_rsp_ind(L2capChannel* channel)
{
channel->cfgState |= L2CAP_CFG_OUT;
if ((channel->cfgState & L2CAP_CFG_BOTH) == L2CAP_CFG_BOTH) {
channel->state = L2CAP_CHAN_OPEN;
return channel->endpoint->MarkEstablished();
}
@ -116,10 +176,9 @@ l2cap_cfg_req_ind(L2capChannel* channel)
if ((channel->cfgState & L2CAP_CFG_BOTH) == L2CAP_CFG_BOTH) {
// Channel can be declared open
channel->state = L2CAP_CHAN_OPEN;
channel->endpoint->MarkEstablished();
} else {
} else if ((channel->cfgState & L2CAP_CFG_IN_SENT) == 0) {
// send configuration Request by our side
if (channel->endpoint->RequiresConfiguration()) {
// TODO: define complete configuration packet