From ef36d9649647a658fecd9053b90252ee0d2f2381 Mon Sep 17 00:00:00 2001 From: Oliver Ruiz Dorantes Date: Sun, 11 Jul 2010 16:57:47 +0000 Subject: [PATCH] - Implement hook Connect() - Polish l2cap signals negotiation git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37472 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../network/protocols/l2cap/L2capEndpoint.cpp | 61 +++++-- .../network/protocols/l2cap/L2capEndpoint.h | 3 +- .../kernel/network/protocols/l2cap/l2cap.cpp | 8 +- .../network/protocols/l2cap/l2cap_command.h | 5 +- .../network/protocols/l2cap/l2cap_lower.cpp | 2 +- .../network/protocols/l2cap/l2cap_signal.cpp | 169 +++++++++++------- .../network/protocols/l2cap/l2cap_upper.cpp | 67 ++++++- 7 files changed, 223 insertions(+), 92 deletions(-) diff --git a/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.cpp b/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.cpp index efb0325dab..7ebc57a9d4 100644 --- a/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.cpp +++ b/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.cpp @@ -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); - if (error == B_OK) { - release_sem(fPeerEndpoint->fAcceptSemaphore); - } else { - debugf("Could not set child Endpoint %p %s\n", this, strerror(error)); - } + fChannel->state = L2CAP_CHAN_OPEN; + + if (fPeerEndpoint != NULL) { + + 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; } diff --git a/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.h b/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.h index 7632a3b7a0..2d18e55aee 100644 --- a/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.h +++ b/src/add-ons/kernel/network/protocols/l2cap/L2capEndpoint.h @@ -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; diff --git a/src/add-ons/kernel/network/protocols/l2cap/l2cap.cpp b/src/add-ons/kernel/network/protocols/l2cap/l2cap.cpp index e663eb3321..0736255c23 100644 --- a/src/add-ons/kernel/network/protocols/l2cap/l2cap.cpp +++ b/src/add-ons/kernel/network/protocols/l2cap/l2cap.cpp @@ -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; } diff --git a/src/add-ons/kernel/network/protocols/l2cap/l2cap_command.h b/src/add-ons/kernel/network/protocols/l2cap/l2cap_command.h index fe4afca915..db47d8017d 100644 --- a/src/add-ons/kernel/network/protocols/l2cap/l2cap_command.h +++ b/src/add-ons/kernel/network/protocols/l2cap/l2cap_command.h @@ -1,4 +1,4 @@ -/* +/* * Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com * All rights reserved. Distributed under the terms of the MIT License. */ @@ -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); diff --git a/src/add-ons/kernel/network/protocols/l2cap/l2cap_lower.cpp b/src/add-ons/kernel/network/protocols/l2cap/l2cap_lower.cpp index 941dd8ef36..c62a6eee56 100644 --- a/src/add-ons/kernel/network/protocols/l2cap/l2cap_lower.cpp +++ b/src/add-ons/kernel/network/protocols/l2cap/l2cap_lower.cpp @@ -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); diff --git a/src/add-ons/kernel/network/protocols/l2cap/l2cap_signal.cpp b/src/add-ons/kernel/network/protocols/l2cap/l2cap_signal.cpp index df85cece82..1e9d2569e2 100644 --- a/src/add-ons/kernel/network/protocols/l2cap/l2cap_signal.cpp +++ b/src/add-ons/kernel/network/protocols/l2cap/l2cap_signal.cpp @@ -45,13 +45,13 @@ typedef enum _option_status { l2cap_flow_t default_qos = { - /* flags */ 0x0, + /* flags */ 0x0, /* service_type */ HCI_SERVICE_TYPE_BEST_EFFORT, - /* token_rate */ 0xffffffff, /* maximum */ + /* token_rate */ 0xffffffff, /* maximum */ /* token_bucket_size */ 0xffffffff, /* maximum */ - /* peak_bandwidth */ 0x00000000, /* maximum */ - /* latency */ 0xffffffff, /* don't care */ - /* delay_variation */ 0xffffffff /* don't care */ + /* peak_bandwidth */ 0x00000000, /* maximum */ + /* latency */ 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 */ 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"); @@ -245,7 +247,7 @@ l2cap_process_con_req(HciConnection* conn, uint8 ident, net_buffer* buffer) status_t indicationStatus = l2cap_l2ca_con_ind(channel); 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) { /* 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); 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,9 +326,10 @@ 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); + // btCoreData->RemoveChannel(conn, cmd->channel->scid); } 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? */ 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,11 +447,10 @@ 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 */ - NetBufferHeaderReader command(buffer); + NetBufferHeaderReader command(buffer); status_t status = command.Status(); if (status < B_OK) { return ENOBUFS; @@ -450,22 +459,26 @@ l2cap_process_cfg_req(HciConnection* conn, uint8 ident, net_buffer* buffer) dcid = le16toh(command->dcid); 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 */ 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 @@ -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); if (error != 0) { // TODO: - //INDICATION ng_l2cap_l2ca_discon_ind(ch); + // INDICATION ng_l2cap_l2ca_discon_ind(ch); btCoreData->RemoveChannel(conn, channel->scid); } } else { @@ -553,9 +569,9 @@ reject: /* Process L2CAP_ConfigRsp command */ 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; l2cap_cfg_opt_t hdr; @@ -564,7 +580,7 @@ l2cap_process_cfg_rsp(HciConnection *conn, uint8 ident, net_buffer *buffer) size_t off; status_t error = 0; - NetBufferHeaderReader command(buffer); + NetBufferHeaderReader command(buffer); status_t status = command.Status(); if (status < B_OK) { return ENOBUFS; @@ -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; } @@ -628,7 +649,7 @@ l2cap_process_cfg_rsp(HciConnection *conn, uint8 ident, net_buffer *buffer) case L2CAP_OPT_QOS: memcpy(&val.flow, &cmd->channel->configuration->oflow, - sizeof(cmd->channel->configuration->oflow)); + sizeof(cmd->channel->configuration->oflow)); break; 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. */ - debugf("failed to parse configuration options, error=%ld\n", error); - //INDICATION + 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; @@ -845,7 +871,7 @@ static status_t l2cap_process_echo_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer) { L2capFrame* cmd = NULL; - status_t error = 0; + status_t error = 0; /* Check if we have this command */ cmd = btCoreData->SignalByIdent(conn, ident); @@ -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; } @@ -875,7 +902,7 @@ l2cap_process_info_req(HciConnection* conn, uint8 ident, net_buffer* buffer) { L2capFrame* cmd = NULL; net_buffer* buf = NULL; - uint16 type; + uint16 type; /* Get command parameters */ NetBufferHeaderReader command(buffer); @@ -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: @@ -919,7 +949,7 @@ l2cap_process_info_rsp(HciConnection* conn, uint8 ident, net_buffer* buffer) status_t error = B_OK; /* Get command parameters */ - NetBufferHeaderReader command(buffer); + NetBufferHeaderReader command(buffer); status_t status = command.Status(); if (status < B_OK) { return ENOBUFS; @@ -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; } @@ -1007,7 +1038,7 @@ l2cap_process_cmd_rej(HciConnection* conn, uint8 ident, net_buffer* buffer) break; 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); break; @@ -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; } @@ -1040,11 +1071,12 @@ l2cap_process_cmd_rej(HciConnection* conn, uint8 ident, net_buffer* buffer) status_t send_l2cap_reject(HciConnection* conn, uint8 ident, uint16 reason, - uint16 mtu, uint16 scid, uint16 dcid) + uint16 mtu, uint16 scid, uint16 dcid) { 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; diff --git a/src/add-ons/kernel/network/protocols/l2cap/l2cap_upper.cpp b/src/add-ons/kernel/network/protocols/l2cap/l2cap_upper.cpp index 3cfe767aa4..050e44bcfb 100644 --- a/src/add-ons/kernel/network/protocols/l2cap/l2cap_upper.cpp +++ b/src/add-ons/kernel/network/protocols/l2cap/l2cap_upper.cpp @@ -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