示例#1
0
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;
}
示例#2
0
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;
}
示例#3
0
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;
}
示例#4
0
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;
}
示例#5
0
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;
}
示例#6
0
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;
}
示例#7
0
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;
}
示例#8
0
/* 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;
}
示例#9
0
/* 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;
}
示例#10
0
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;
}