status_t l2cap_cfg_req_ind(L2capChannel* channel) { // if our configuration has not been yet sent ... if (!(channel->cfgState & L2CAP_CFG_OUT_SENT)) { // TODO: check if we can handle this conf // send config_rsp net_buffer* buf = l2cap_cfg_rsp(channel->ident, channel->dcid, 0, L2CAP_SUCCESS, NULL); L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf, channel->ident, L2CAP_CFG_RSP); if (cmd == NULL) { gBufferModule->free(buf); channel->state = L2CAP_CHAN_CLOSED; return ENOMEM; } // Link command to the queue SchedConnectionPurgeThread(channel->conn); // set status channel->cfgState |= L2CAP_CFG_OUT_SENT; } if ((channel->cfgState & L2CAP_CFG_BOTH) == L2CAP_CFG_BOTH) { // Channel can be declared open channel->endpoint->MarkEstablished(); } else if ((channel->cfgState & L2CAP_CFG_IN_SENT) == 0) { // send configuration Request by our side if (channel->endpoint->RequiresConfiguration()) { // TODO: define complete configuration packet } else { // nothing special requested channel->ident = btCoreData->ChannelAllocateIdent(channel->conn); net_buffer* buf = l2cap_cfg_req(channel->ident, channel->dcid, 0, NULL); L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf, channel->ident, L2CAP_CFG_REQ); if (cmd == NULL) { gBufferModule->free(buf); channel->state = L2CAP_CHAN_CLOSED; return ENOMEM; } // Link command to the queue SchedConnectionPurgeThread(channel->conn); } channel->cfgState |= L2CAP_CFG_IN_SENT; } return B_OK; }
status_t l2cap_l2ca_con_ind(L2capChannel* channel) { L2capEndpoint* endpoint = L2capEndpoint::ForPsm(channel->psm); if (endpoint == NULL) { // TODO: refuse connection no endpoint bound debugf("No endpoint bound for psm %d\n", channel->psm); return B_ERROR; } // Pair Channel with endpoint endpoint->BindToChannel(channel); net_buffer* buf = l2cap_con_rsp(channel->ident, channel->scid, channel->dcid, L2CAP_SUCCESS, L2CAP_NO_INFO); L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf, channel->ident, L2CAP_CON_RSP); if (cmd == NULL) { gBufferModule->free(buf); return ENOMEM; } // we can move to configuration... channel->state = L2CAP_CHAN_CONFIG; // Link command to the queue SchedConnectionPurgeThread(channel->conn); return B_OK; }
status_t 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); if (cmd == NULL) return ENOMEM; /* Link command to the queue */ SchedConnectionPurgeThread(conn); return B_OK; }
status_t send_l2cap_reject(HciConnection* conn, uint8 ident, uint16 reason, 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); if (cmd == NULL) return ENOMEM; /* Link command to the queue */ SchedConnectionPurgeThread(conn); return B_OK; }
static status_t 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); if (cmd == NULL) { gBufferModule->free(buffer); return ENOMEM; } /* Attach data and link command to the queue */ SchedConnectionPurgeThread(conn); return B_OK; }
status_t 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); if (cmd == NULL) { gBufferModule->free(opt); return ENOMEM; } /* Link command to the queue */ SchedConnectionPurgeThread(conn); return B_OK; }
status_t l2cap_upper_con_req(L2capChannel* channel) { channel->ident = btCoreData->ChannelAllocateIdent(channel->conn); net_buffer* buf = l2cap_con_req(channel->ident, channel->psm, channel->scid); L2capFrame* cmd = btCoreData->SpawnSignal(channel->conn, channel, buf, channel->ident, L2CAP_CON_REQ); if (cmd == NULL) { gBufferModule->free(buf); return ENOMEM; } channel->state = L2CAP_CHAN_W4_L2CAP_CON_RSP; // Link command to the queue SchedConnectionPurgeThread(channel->conn); return B_OK; }
/* Process L2CAP_InfoReq command */ static status_t l2cap_process_info_req(HciConnection* conn, uint8 ident, net_buffer* buffer) { L2capFrame* cmd = NULL; net_buffer* buf = NULL; uint16 type; /* Get command parameters */ NetBufferHeaderReader<l2cap_info_req_cp> command(buffer); status_t status = command.Status(); if (status < B_OK) { return ENOBUFS; } //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); break; default: buf = l2cap_info_rsp(ident, type, L2CAP_NOT_SUPPORTED, 0); break; } cmd = btCoreData->SpawnSignal(conn, NULL, buf, ident, L2CAP_INFO_RSP); if (cmd == NULL) return ENOMEM; /* Link command to the queue */ SchedConnectionPurgeThread(conn); return B_OK; }
/* Process L2CAP_DisconnectReq command */ static status_t l2cap_process_discon_req(HciConnection* conn, uint8 ident, net_buffer* buffer) { L2capChannel* channel = NULL; L2capFrame* cmd = NULL; net_buffer* buff = NULL; uint16 scid; uint16 dcid; NetBufferHeaderReader<l2cap_discon_req_cp> command(buffer); status_t status = command.Status(); if (status < B_OK) { return ENOBUFS; } dcid = le16toh(command->dcid); scid = le16toh(command->scid); command.Remove(); /* Check if we have this channel and it is in valid state */ channel = btCoreData->ChannelBySourceID(conn, dcid); if (channel == NULL) { debugf("unexpected L2CAP_DisconnectReq message.Channel does not exist, " "cid=%d\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) { debugf("unexpected L2CAP_DisconnectReq. Invalid channel state, cid=%d, " "state=%d\n", dcid, channel->state); goto reject; } /* Match destination channel ID */ if (channel->dcid != scid || channel->scid != dcid) { debugf("unexpected L2CAP_DisconnectReq. Channel IDs does not match, " "channel: scid=%d, dcid=%d, request: scid=%d, dcid=%d\n", channel->scid, channel->dcid, scid, dcid); goto reject; } /* * Looks good, so notify upper layer protocol that channel is about * to be disconnected and send L2CA_DisconnectInd message. Then respond * with L2CAP_DisconnectRsp. */ flowf("Responding\n"); // inform upper if we were not actually already waiting if (channel->state != L2CAP_CHAN_W4_L2CAP_DISCON_RSP) { l2cap_l2ca_discon_ind(channel); // do not care about result } /* Send L2CAP_DisconnectRsp */ buff = l2cap_discon_rsp(ident, dcid, scid); cmd = btCoreData->SpawnSignal(conn, channel, buff, ident, L2CAP_DISCON_RSP); if (cmd == NULL) return ENOMEM; /* Link command to the queue */ SchedConnectionPurgeThread(conn); btCoreData->RemoveChannel(conn, channel->scid); return B_OK; reject: flowf("Rejecting\n"); /* Send reject. Do not really care about the result */ send_l2cap_reject(conn, ident, L2CAP_REJ_INVALID_CID, 0, scid, dcid); return B_OK; }
status_t l2cap_con_rsp_ind(HciConnection* conn, L2capChannel* channel) { uint16* flush_timo = NULL; uint16* mtu = NULL; l2cap_flow_t* flow = NULL; CALLED(); // 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) { ERROR("%s: unexpected L2CA_Config request message. Invalid channel" " state, state=%d, lcid=%d\n", __func__, 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; } TRACE("%s: Sending cfg req\n", __func__); // Link command to the queue SchedConnectionPurgeThread(channel->conn); return B_OK; }